Domanda

sto usando JPA 2.0 validazione / Hibernate per convalidare i miei modelli. Ora ho una situazione in cui la combinazione di due campi deve essere convalidato:

public class MyModel {
    public Integer getValue1() {
        //...
    }
    public String getValue2() {
        //...
    }
}

Il modello è non valida se entrambi getValue1() e getValue2() sono null e valido altrimenti.

Come posso eseguire questo tipo di convalida con JPA 2.0 / Hibernate? Con una semplice annotazione @NotNull entrambi getter devono essere non nullo per passare convalida.

È stato utile?

Soluzione

Per più proprietà di convalida, è necessario utilizzare i vincoli a livello di classe. A partire dal Bean Validation Sneak Peek parte II: custom vincoli :

  

vincoli a livello di classe

     

Alcuni di voi hanno espresso preoccupazioni   circa la capacità di applicare una   vincolo di Multiple Spanning   proprietà, o per vincolo espresso   che dipendono diverse proprietà.   L'esempio classico è l'indirizzo   convalida. Indirizzi hanno intricato   regole:

     
      
  • un nome della via è in qualche modo standard e deve certamente avere un limite di lunghezza
  •   
  • la struttura del codice di avviamento postale dipende interamente il paese
  •   
  • la città può spesso essere correlata a un codice postale e un po 'il controllo degli errori lattina   essere fatto (a condizione che una validazione   servizio è accessibile)
  •   
  • a causa di queste interdipendenze un vincolo semplice livello di proprietà fa   per adattarsi al disegno di legge
  •   
     

La soluzione offerta dal Bean   specifica convalida è duplice:

     
      
  • che offre la possibilità di forzare un insieme di vincoli da applicare prima di un   altra serie di vincoli attraverso la   utilizzare dei gruppi e sequenze di gruppo.   Questo argomento sarà trattato nel   prossimo blog
  •   
  • permette di definire i vincoli livello di classe
  •   
     

vincoli livello di classe sono regolari   vincoli (annotazioni /   attuazione duo) applicabili su   classe piuttosto che una proprietà. Disse   diversamente, i vincoli a livello di classe   ricevere l'istanza di oggetto (piuttosto   che il valore della proprietà) in isValid.

@AddressAnnotation 
public class Address {
    @NotNull @Max(50) private String street1;
    @Max(50) private String street2;
    @Max(10) @NotNull private String zipCode;
    @Max(20) @NotNull String city;
    @NotNull private Country country;

    ...
}

@Constraint(validatedBy = MultiCountryAddressValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AddressAnnotation {
    String message() default "{error.address}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}

public class MultiCountryAddressValidator implements ConstraintValidator<AddressAnnotation, Address> {
    public void initialize(AddressAnnotation constraintAnnotation) {
    // initialize the zipcode/city/country correlation service
    }

    /**
     * Validate zipcode and city depending on the country
     */
    public boolean isValid(Address object, ConstraintValidatorContext context) {
        if (!(object instanceof Address)) {
            throw new IllegalArgumentException("@Address only applies to Address");
        }
        Address address = (Address) object;
        Country country = address.getCountry();
        if (country.getISO2() == "FR") {
            // check address.getZipCode() structure for France (5 numbers)
            // check zipcode and city correlation (calling an external service?)
            return isValid;
        } else if (country.getISO2() == "GR") {
            // check address.getZipCode() structure for Greece
            // no zipcode / city correlation available at the moment
            return isValid;
        }
        // ...
    }
}
     

Le regole di convalida degli indirizzi avanzata   sono stati lasciati fuori dell'indirizzo   oggetto e realizzato da   MultiCountryAddressValidator. Di   Accedendo l'istanza dell'oggetto, classe   vincoli di livello hanno un sacco di   flessibilità e in grado di convalidare multipla   Proprietà correlate. Nota che   ordinamento viene lasciato fuori dall'equazione   qui, torneremo ad esso in   prossimo post.

     

Il gruppo di esperti ha discusso varie   più proprietà supporto   approcci: pensiamo che il livello di classe   approccio vincolo fornisce sia   abbastanza semplicità e flessibilità   rispetto ad altri livello di proprietà   approcci che coinvolgono le dipendenze.   Il tuo feedback è benvenuto.

Altri suggerimenti

Per funzionare correttamente con Bean Validation , l'esempio fornito in Pascal Thivent di rispondere potrebbe essere riscritto come segue:

@ValidAddress
public class Address {

    @NotNull
    @Size(max = 50)
    private String street1;

    @Size(max = 50)
    private String street2;

    @NotNull
    @Size(max = 10)
    private String zipCode;

    @NotNull
    @Size(max = 20)
    private String city;

    @Valid
    @NotNull
    private Country country;

    // Getters and setters
}
public class Country {

    @NotNull
    @Size(min = 2, max = 2)
    private String iso2;

    // Getters and setters
}
@Documented
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = { MultiCountryAddressValidator.class })
public @interface ValidAddress {

    String message() default "{com.example.validation.ValidAddress.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
public class MultiCountryAddressValidator 
       implements ConstraintValidator<ValidAddress, Address> {

    public void initialize(ValidAddress constraintAnnotation) {

    }

    @Override
    public boolean isValid(Address address, 
                           ConstraintValidatorContext constraintValidatorContext) {

        Country country = address.getCountry();
        if (country == null || country.getIso2() == null || address.getZipCode() == null) {
            return true;
        }

        switch (country.getIso2()) {
            case "FR":
                return // Check if address.getZipCode() is valid for France
            case "GR":
                return // Check if address.getZipCode() is valid for Greece
            default:
                return true;
        }
    }
}

Un validatore livello di classe personalizzato è la strada da percorrere, se si vuole stare con la specifica Bean Validation, ad esempio qui .

Se siete felici di utilizzare una funzione Hibernate Validator, è possibile utilizzare @ ScriptAssert , che viene fornito dal Validator-4.1.0.Final. Exceprt dalla sua JavaDoc:

  

espressioni script può essere scritto in qualsiasi script o espressione   lingua, per la quale un JSR 223 ( "Scripting per la piattaforma JavaTM")   il motore compatibile può essere trovato nel classpath.

Esempio:

@ScriptAssert(lang = "javascript", script = "_this.value1 != null || _this != value2)")
public class MyBean {
  private String value1;
  private String value2;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top