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?
Pour que la validation de bean JSR-303 fonctionne au printemps, plusieurs éléments sont nécessaires:
<mvc:annotation-driven />
validation-api-1.0.0.GA.jar
(on dirait que vous l'avez déjà)hibernate-validator-4.1.0.Final.jar
@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....
}
}
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.
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
}
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
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
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
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.
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
Vous devez ajouter @Valid àchaque variable membre, qui était également un objet contenant des contraintes de validation.
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.