web-dev-qa-db-fra.com

Les annotations de javax.validation.constraints ne fonctionnent pas

Quelle configuration est nécessaire pour utiliser des annotations à partir de javax.validation.constraints comme @Size, @NotNull, etc.? Voici mon code:

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Person {
      @NotNull
      private String id;

      @Size(max = 3)
      private String name;

      private int age;

      public Person(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
      }
}

Lorsque j'essaie de l'utiliser dans une autre classe, la validation ne fonctionne pas (c'est-à-dire que l'objet est créé sans erreur):

Person P = new Person(null, "Richard3", 8229));

Pourquoi cela n’applique-t-il pas des contraintes pour id et name? Que dois-je faire d'autre?

39
Darshan Patil

Pour que la validation de bean JSR-303 fonctionne au printemps, plusieurs éléments sont nécessaires:

  1. Configuration de l'espace de noms MVC pour les annotations: <mvc:annotation-driven />
  2. Le fichier JAR des spécifications JSR-303: validation-api-1.0.0.GA.jar (on dirait que vous l'avez déjà)
  3. Une implémentation de la spécification, telle que la validation Hibernate, qui semble être l'exemple le plus couramment utilisé: hibernate-validator-4.1.0.Final.jar
  4. Dans le bean à valider, les annotations de validation, à partir du JAR de spécification ou du JAR d'implémentation (ce que vous avez déjà fait)
  5. Dans le gestionnaire que vous souhaitez valider, annotez l'objet à valider avec @Valid, puis incluez une BindingResult dans la signature de la méthode pour capturer les erreurs. 

Exemple:

@RequestMapping("handler.do")
public String myHandler(@Valid @ModelAttribute("form") SomeFormBean myForm, BindingResult result, Model model) {
    if(result.hasErrors()) {
      ...your error handling...
    } else {
      ...your non-error handling....
    }
}
46
atrain

Vous devez utiliser Validator pour vérifier si votre classe est valide.

Person person = ....;
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Set<ConstraintViolation<Person>> violations = validator.validate(person);

Ensuite, en itérant les violations définies, vous pouvez trouver des violations.

21
Artem

Vous devrez appeler un validateur sur l'entité si vous souhaitez le valider. Ensuite, vous obtiendrez un ensemble de ConstraintViolationException, qui montre fondamentalement pour quel (s) champ (s) de votre entité il y a violation de contrainte et ce qui était exactement . Peut-être pouvez-vous également partager une partie du code que vous prévoyez de valider votre entité.

Une technique souvent utilisée consiste à valider dans @PrePersist et à annuler une transaction si plusieurs modifications de données sont utilisées pendant la transaction ou à effectuer d'autres actions lorsque vous obtenez une exception de validation. 

Votre code devrait ressembler à ceci:

@PrePersist
public void prePersist(SomeEntity someEntity){
    Validator validator = Validation.buildDefaultValidatorFactory.getValidator();
    Set<ConstraintViolation<SomeEntity>> = validator.validate(someEntity);
    //do stuff with them, like notify client what was the wrong field, log them, or, if empty, be happy
}
5
Nikola Yovchev

Vous pouvez également simplement utiliser @NonNull avec la bibliothèque lombok à la place, au moins pour le scénario @NotNull. Plus de détails: https://projectlombok.org/api/lombok/NonNull.html

4
Andreas Dietrich

dans mon cas, j'avais une contrainte personnalisée au niveau de la classe qui n'était pas appelée.

@CustomValidation // not called
public class MyClass {
    @Lob
    @Column(nullable = false)
    private String name;
}

dès que j'ai ajouté une contrainte au niveau du champ à ma classe, personnalisée ou standard, la contrainte au niveau de la classe a commencé à fonctionner.

@CustomValidation // now it works. super.
public class MyClass {
    @Lob
    @Column(nullable = false)
    @NotBlank // adding this made @CustomValidation start working
    private String name;
}

semble être un comportement buggy pour moi, mais assez facile à contourner, je suppose

1
ChetPrickles

Je viens ici quelques années après, et je pourrais y remédier grâce au commentaire de atrain 's ci-dessus . Dans mon cas, il me manquait @Valid dans API qui reçoit l'objet (un POJO dans mon cas) annoté avec @Size. Cela a résolu le problème.

Je n'ai pas besoin d'ajouter une annotation supplémentaire, telle que @Valid ou @NotBlank à la variable annotée avec @Size, juste cette contrainte dans la variable et ce que j'ai mentionné dans l'API ...

Pojo Classe:

...
@Size(min = MIN_LENGTH, max = MAX_LENGTH);
private String exampleVar;
...

Classe API:

...
public void exampleApiCall(@RequestBody @Valid PojoObject pojoObject){
  ...
}

Merci et à la vôtre

0
xCovelus

pour les paramètres de méthode, vous pouvez utiliser Objects.requireNonNull () comme ceci: test(String str) { Objects.requireNonNull(str); } Mais ceci n’est vérifié qu’au moment de l’exécution et jette un NPE si la valeur est null. C'est comme une vérification des conditions préalables. Mais c'est peut-être ce que vous recherchez.

0
Edward

Donc, @Valid au service interface ne fonctionnerait que pour cet objet. Si vous avez d'autres validations dans la hiérarchie de l'objet ServiceRequest, vous devrez peut-être explicitement déclencher des validations. Donc voici comment je l'ai fait:

public class ServiceRequestValidator {

      private static Validator validator;

      @PostConstruct
      public void init(){
         validator = Validation.buildDefaultValidatorFactory().getValidator();
      }

      public static <T> void validate(T t){
        Set<ConstraintViolation<T>> errors = validator.validate(t);
        if(CollectionUtils.isNotEmpty(errors)){
          throw new ConstraintViolationException(errors);
        }
     }

}

Vous devez avoir les annotations suivantes au niveau de l'objet si vous souhaitez déclencher la validation de cet objet.

@Valid
@NotNull
0
Akshay

Vous devez ajouter @Valid àchaque variable membre, qui était également un objet contenant des contraintes de validation.

0
Chad

Excellente réponse de atrain, Mais une meilleure solution pour intercepter des exceptions consiste à utiliser son propre HandlerExceptionResolver

@Override
public ModelAndView resolveException(
    HttpServletRequest aReq, 
    HttpServletResponse aRes,
    Object aHandler, 
    Exception anExc
){
    // ....
    if(anExc instanceof MethodArgumentNotValidException) // do your handle     error here
}

Vous pourrez alors garder votre gestionnaire le plus propre possible . Vous n’avez plus besoin de BindingResult, Model et SomeFormBean dans myHandlerMethod.

0
PavelP