Validation de bean
L'API de validation de bean (Bean Validation API) est introduite avec la plateforme Java™ Enterprise Edition 6 en tant que mécanisme standard à utiliser pour valider les JavaBeans dans toutes les couches d'une application, notamment la couche de présentation, la couche métier (business) et la couche d'accès aux données.
Avant l'introduction de la spécification Bean Validation, les JavaBeans étaient validés dans chaque couche. Pour empêcher la réimplémentation des validations à chaque couche, les développeurs regroupaient directement les validations dans leurs classes ou copiaient le code de validation, qui était souvent confus. Désormais, avec une seule implémentation commune à toutes les couches de l'application, les développeurs voient leur travail simplifié et gagnent un temps précieux.
La spécification Bean Validation définit un modèle de métadonnées et une API qui sont utilisés pour valider l'intégrité des données manipulées par les JavaBeans. La source des métadonnées est constituée des annotations de contrainte, lesquelles peuvent être redéfinies et étendues au moyen de descripteurs de validation XML. Le jeu d'API fournit un modèle de programmation simple d'emploi, permettant à n'importe quelle couche de l'application d'utiliser le même jeu de contraintes de validation. Les contraintes de validation servent à contrôler la valeur des champs, méthodes et types annotés afin de vérifier qu'ils obéissent aux contraintes définies.
L'utilisateur peut employer les contraintes standard (telles que définies par la spécification officielle) ou définir ses propres contraintes. Plusieurs annotations standard sont disponibles dans le package javax.validation.constraints. Elles servent à créer des définitions de contraintes à base d'expressions régulières et sont également utilisées pour composer des contraintes. Pour la liste de ces contraintes standard, consultez les informations sur les contraintes standard pour la validation des beans. Pour plus de détails sur le modèle de métadonnées et les API de validation de bean, consultez le document de spécification JSR 349 Bean Validation.
L'exemple suivant est une simple classe d'EJB (Enterprise JavaBeans) décorée avec des annotations de contraintes standard.
public class Home {
@Size(Max=20)
String builder;
@NotNull @Size(Max=20)
String address;
public String getAddress() {
return address;
}
public String getBuilder() {
return address;
}
public String setAddress(String newAddress) {
return address = newAddress;
}
public String setBuilder(String newBuilder) {
return builder = newBuilder;
}
}
Les annotations @Size décorant les champs builder et address stipulent que la valeur de chaîne affectée à ces champs ne doit pas dépasser 20 caractères. L'annotation @NotNull accompagnant le champ address indique que la valeur de celui-ci ne peut pas être Null. Lors de la validation de l'objet Home, les valeurs de builder et address sont chacune passées à la classe de valideur (Validator) définie pour l'annotation @Size. La valeur du champ address est également passée à la classe de valideur ayant en charge l'annotation @NotNull. Les classes de valideur s'occupent de vérifier les valeurs des contraintes qui leur sont dévolues et, si une contrainte échoue à la validation, un objet ConstraintViolation est créé et renvoyé dans un ensemble à l'appelant ayant demandé la validation de l'objet Home.
API de validation
Le package javax.validation contient les API de validation de bean qui décrivent comment valider programmatiquement des JavaBeans.
ConstraintViolation est la classe qui décrit une violation de contrainte particulière. Pour la validation d'un objet, un ensemble de classes ConstraintViolation est renvoyé. La violation de contrainte expose également un message lisible par l'utilisateur, décrivant la violation en question.
Des exceptions ValidationException sont émises si un échec se produit durant la validation.
L'interface Validator est la principale API de validation. Une instance de Validator est l'objet qui est capable de valider les valeurs des champs, méthodes et types d'un objet Java. L'API d'amorçage (bootstrapping) est le mécanisme utilisé pour accéder à une fabrique ValidatorFactory, laquelle est utilisée pour créer une instance de Validator. Pour les applications déployées sur notre produit, l'amorçage est réalisé automatiquement. Les applications peuvent obtenir le valideur ou la fabrique ValidatorFactory de deux manières. La première consiste à utiliser l'injection, par exemple, en utilisant l'annotation @Resource et la seconde, à utiliser la recherche java:.
@Resource ValidatorFactory _validatorFactory;
@Resource Validator _validator;
ValidatorFactory validatorFactory = (ValidatorFactory)context.lookup("java:comp/ValidatorFactory");
Validator validator = (Validator)context.lookup("java:comp/Validator");
API de demande des métadonnées de contrainte
Les API de métadonnées assurent le support des fournisseurs d'outils et réalisent l'intégration avec d'autres infrastructures, bibliothèques et technologies Java Platform, Enterprise Edition. L'accès au référentiel de métadonnées des contraintes d'un objet se fait à travers l'instance de Validator de la classe considérée.
Descripteurs de déploiement XML
Outre la déclaration de contraintes dans les annotations, il existe un support pour vous permettre de déclarer vos contraintes à l'aide de code XML.
La description XML de la validation est composée de deux types de fichier .xml. Le fichier META-INF/validation.xml décrit la configuration de validation de bean pour le module considéré. L'autre type de fichier XML décrit les déclarations de contraintes et correspond étroitement à la méthode de déclaration des annotations. Par défaut, toutes les déclarations de contraintes exprimées via des annotations sont ignorées pour les classes décrites dans le code XML. Il n'est pas possible de forcer la validation à utiliser à la fois les annotations est les déclarations de contraintes XML en utilisant le réglage ignore-annotation="false" sur le bean. Notre produit veille à ce que chaque module d'application déployé qui contient un fichier validation.xml et des contraintes définies dans un fichier XML soit isolé des fichiers validation.xml et de contraintes des autres modules. A cet effet, il crée des instances de Validator spécifiques au module contenant les descripteurs XML.
Concepts avancés de validation de bean
L'API Bean Validation fournit un ensemble de contraintes standard, ainsi qu'une interface qui vous permet de déclarer vos propres contraintes. Pour ce faire, vous créez des annotations de contraintes. Ensuite, lorsque vous souhaitez appliquer l'une de vos contraintes, vous déclarez l'annotation sur le type, le champ ou la propriété de bean concernés. La composition de contraintes est également réalisée en déclarant la contrainte sur une autre définition de contrainte.
L'exemple suivant illustre la création d'une contrainte CommentChecker (littéralement, vérificateur de commentaire) qui est définie pour s'assurer qu'une zone de chaîne de commentaire n'est pas Null. Le texte du commentaire est mis entre crochets, comme ceci : [texte].
package com.my.company;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Constraint(validatedBy = CommentValidator.class)
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface CommentChecker {
String message() default "The comment is not valid.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
…}
package com.my.company;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CommentValidator implements ConstraintValidator<CommentChecker, String> {
public void initialize(CommentChecker arg0) {
}
public boolean isValid(String comment, ConstraintValidatorContext context) {
if (comment == null) {
// Null comment is not allowed, fail the constraint.
return false;
}
if (!comment.contains("[") && !comment.contains("]")) {
// Can't find any open or close brackets, fail the constraint
return false;
}
// Ignore leading and trailing spaces
String trimmedComment = comment.trim();
return // validate '[' prefix condition
trimmedComment.charAt(0) == '[' &&
// validate ']' suffix condition
trimmedComment.charAt(trimmedComment.length()!-1) == ']';
}
}
Une fois l'annotation @CommentChecker définie,
on peut l'utiliser pour s'assurer que le champ de chaîne de commentaire
est un commentaire valide, selon
l'implémentation de la méthode isValid() dans la classe CommentValidator. L'exemple suivant illustre l'utilisation de
la contrainte @CommentChecker. Lors de la validation du bean myChecker, la chaîne de commentaire
est validée par la classe
CommentValidator pour vérifier que les contraintes définies sont
satisfaites. package com.my.company;
public myChecker {
@CommentChecker
String comment = null;
...
}
Notre produit possède un fournisseur de validation de bean par défaut, mais vous pouvez en utiliser un autre dans votre application. Vous pouvez choisir un autre fournisseur à l'aide d'un programme, en appelant la méthode javax.validation.Validation.byProvider() pour créer une fabrique de validation. Vous pouvez également choisir un autre fournisseur de manière déclarative en spécifiant l'élément <default-provider/> dans le fichier validation.xml. Pour être sûr que les classes de cet autre fournisseur ne sont pas en conflit avec le fournisseur par défaut, affectez à l'ordre du chargeur de classe d'application ou de serveur la valeur Classes chargées en premier avec un chargeur de classe local (dernier parent). Pour des informations supplémentaires sur la définition de ce paramètre, consultez la documentation consacrée au chargement des classes.
La spécification Bean Validation stipule que si plusieurs fichiers validation.xml sont trouvés dans le chemin des classes, une exception ValidationException est émise. Cependant, WebSphere Application Server prévoit le cas d'un environnement dans lequel plusieurs équipes développent différents modules qui sont ensuite assemblés et déployés ensemble dans le serveur d'applications. Dans cet environnement, tous les modules EJB au sein d'une application sont chargés avec le même chargeur de classe, et il est possible de configurer les chargeurs de classe de l'application de sorte que tous les modules EJB et WAR (archives Web) soient chargés par un seul et même chargeur de classe. Pour cette raison, notre produit déroge à la spécification officielle et admet la présence de plusieurs fichiers validation.xml dans le même chemin de classes.
<constraint-mapping>META-INF/constraints-house.xml</constaint-mapping>
<constraint-mapping>META-INF/constraints-rooms.xml</constraint-mapping>
Il est fait exception à ce comportement lorsque toutes les classes des contraintes de validation de bean et toutes les configurations associées sont visibles par tous les modules d'application. Dans le cas où un seul fichier validation.xml est défini dans un fichier EAR et qu'aucun autre fichier validation.xml n'est visible dans le chemin des classes d'un module, tous les modules créant une fabrique de valideur ou un valideur utilisent le fichier validation.xml qui est défini dans le fichier EAR. Cela permet aux autres modules de créer une fabrique de valideur qui utilise le fichier validation.xml d'un autre module, si le chemin des classes a été configuré de sorte que les deux modules soient visibles sur le même chemin de classes et qu'un seul fichier validation.xml soit visible par ces modules.
Pour plus de détails sur le modèle de métadonnées et les API de validation de bean, consultez le document de spécification JSR 349 Bean Validation.