Validation JSR-303

Vérifier les données avec JSR-303

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

La spécification JSR 303 permet de valider les objets POJO grâce à des annotations ou un fichier de configuration XML. La validation JSR 303 Bean est donc un outil très flexible grâce auquel on peut vérifier la conformité des données.

JSR 303 Bean Validation est placée dans le package javax.validation. Il contient 5 autres sous-packages :
- javax.validation.bootstrap
- javax.validation.constraints
- javax.validation.groups
- javax.validation.metadata
- javax.validation.spi

Dans cet article on se concentrera sur les contraintes (javax.validation.constraints). Les autres parties seront rapidement parcourues.

Boostrap

Ce sous-package configure le fournisseur de validation. Il contient deux interfaces qui permettent d'initialiser Bean Validation. L'exemple de l'implémenetation d'une de ces interfaces est org.hibernate.validator.HibernateValidator de l'ORM Hibernate.

On constate que ce validateur permet de configurer plusieurs aspects de son fonctionnement avant l'exécution de la procédure de validation :
- MessageInterpolator : interprétateur lancé quand la validation pour un attribut échoue. Il a pour but de gérer les messages d'erreur retournés.
- TraversableResolver : détermine si une propriété peut être accédée par le fournisseur Bean Validation. Cette fonctionnalité peut être utile lors de la validation des éléments associés avec Java Persistence ou aussi bien pour des éléments chargés avec lazy loading.
- ConstraintValidatorFactory : initialise ConstraintValidator.

Constraints

Cette partie est essentielle car elle regroupe les contraintes de validation disponibles dans la spécification. Voici la liste des contraintes possibles : - AssertFalse / AssertTrue : l'élément doit renvoyer false (AssertFalse) ou true (AsserTrue). Dans le cas contraire, la validation échoue. - DecimalMax / DecimalMin : la valeur maximale et minimale de la décimale. - Digits : l'élément doit être numérique (les types acceptés : BigDecimal BigInteger String byte, short, int, long). Si l'élément est null, il est considéré comme valide. - Future / Past : la valeur doit être soit dans le futur, soit dans le passé. - Max / Min : la longueur maximale et minimale d'un élément. - NotNull / Null : l'élément doit être instance d'une classe (NotNull) ou null (Null). - Pattern : l'élément doit correspondre à l'expression régulière comprise dans cette annotation. - Size : la valeur de la largueur d'élément doit être comprise entre attributs minimum - maximum exprimés avec min et max. Cette contrainte s'applique à des types suivants : String, Collection, Map, Array (la taille est alors évaluée). Les éléments null sont considérés comme valides.

On peut également aller plus loin et concevoir une contrainte personnalisé. Elle doit hériter de la classe ConstraintValidator. La validation s'effectue dans sa méthode isValid() qui renvoie false en cas d'échec et true en cas d'une validation correcte. Voici l'exemple d'une contrainte personnalisée :

afficher le code

Et l'affichage du résultat sur l'écran :

Violation found ConstraintViolationImpl{interpolatedMessage='Check if is equal',
 propertyPath=name, rootBeanClass=class Pupil, messageTemplate='Check if is equal'}

Groups

Cette partie permet de grouper les contraintes de validation. Elle peut s'avérer très utile lors de validation des attributs dans le cas d'héritage d'une classe.

Pour voir à quoi cela peut correspondre, imaginons la situation où l'on valide une entité représentant un écolier à de différents stades de vie :

public class Pupil {
    protected String name;
}

class PupilPrimarySchool extends Pupil {
    @Min(1)
    private int note;
}

class PupilHighSchool extends Pupil {
    @Min(1, groups = CheckHighSchool.class)
    private int primaryNote;
    
    @Min(1)
    private int highSchoolNote;
}

Pour déclencher la validation uniquement pour le groupe CheckHighSchool, il suffit alors d'appeler le validateur de cette manière :

validator.validate(pupilHigh, CheckHighSchool.class );

Metadata

Grâce à ce sous-package il est possible de lire les contraintes qui sont attachées à une entité. Pour le constater regardons le code ci-dessous :

afficher le code

On pourra voir le résultat d'output sur l'écran :

Constraints size for property name = 2
Found new annotation's constraint : @javax.validation.constraints.NotNull(message={javax.validation.constraints.NotNull.message}, payload=[], groups=[])
Found new annotation's constraint : @javax.validation.constraints.Min(message=Min length is 2, payload=[], groups=[], value=2)
Constraints size for property gender = 2
Found new annotation's constraint : @javax.validation.constraints.NotNull(message={javax.validation.constraints.NotNull.message}, payload=[], groups=[])
Found new annotation's constraint : @javax.validation.constraints.Max(message=Max length is 3, payload=[], groups=[], value=3)

Pour éxecuter cet exemple on aura besoin des fichiers joints (Hibernate Validator 4.0.3 et Validation API 1.0.0).

Spi

Les implémentation des interfaces de cette partie permettent de manipuler la configuration du validateur. A la base, le fichier de configuration devrait être placé dans le répertoire META-INF/validation.xml.

Bartosz KONIECZNY Packages

Une question ? Une remarque ?

*

*

Un conseil JavaScript

Comment accéder aux éléments du parent avec jQuery ?

jQuery, le célèbre framework JavaScript, permet d'écrire moins et de faire plus. On pourrait s'imaginer que cela s'applique uniquement aux opérations basiques, limitées au sein d'un seul document / d'une seule fenêtre. Cependant, avec jQuery on peut aussi manipuler les éléments d'une fenêtre-enfant. Ces opérations se limitent à la précision qu'il s'agit du document parent. Supposons qu'on ouvre une popup et qu'on veut récupérer les informations appartenant aux div avec l'identifiant "CONTENT" situé dans le document parent. Pour ce faire, il suffit de préciser qu'il s'agit du document supérieur :

$('#CONTENT', window.parent.document).html();