Valider la combinaison de plusieurs champs

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Je suis en train (pour le boulot), de créer une API rest en java avec jetty, hk2 comme IOC, et java 8.

Je me trouve coincé lorsqu’il faut que je valide mes ressources d’entrée. En effet fonctionnellement parlant il m’est spécifié que deux champs peuvent être nuls mais pas les deux en même temps. J’aimerais pouvoir intégrer cette contrainte dans le flux de validation que permet JAX-RS avec l’API javax.validation.constraints.

Voici ma ressource de base (StatusType est une énum):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class AnalysisInput {
    @javax.validation.constraints.Pattern(regexp = "^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!10(?:\\.\\d{1,3}){3})" +
            "(?!127(?:\\.\\d{1,3}){3})(?!169\\.254(?:\\.\\d{1,3}){2})(?!192\\.168(?:\\.\\d{1,3}){2})" +
            "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
            "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
            "|(?:(?:[a-z\\x{00a1}-\\x{ffff}0-9]+-?)*[a-z\\x{00a1}-\\x{ffff}0-9]+)" +
            "(?:\\.(?:[a-z\\x{00a1}-\\x{ffff}0-9]+-?)*[a-z\\x{00a1}-\\x{ffff}0-9]+)*(?:\\.(?:[a-z\\x{00a1}-\\x{ffff}]{2,})))" +
            "(?::\\d{2,5})?(?:/[^\\s]*)?$_iuS", message = "Url is not valid.")
    private String url;
    private String document;
    private List<TokenInput> token;
// constructeur + accesseur 
// ...
//

    public boolean hasDocument() {
        return document != null && !"".equals(document);
    }

    public boolean hasToken() {
        return !isDocument() && !token.isEmpty();
    }
}

Globalement, je veux que hasDocument et hasToken ne puisse pas être faux en même temps.

Comment puis-je faire?

+0 -0

Cette réponse a aidé l’auteur du sujet

Globalement, je veux que hasDocument et hasToken ne puisse pas être faux en même temps.

C’est la définition du ou logique (||). Juste pour être sur, ce que tu demandes, c’est comment utiliser l’API javax.validation.constraints pour ajouter cette contrainte ?

Edit : une solution pourrait être d’écrire une troisième méthode checkSpecs qui rende un booléen (hasDocument || hasToken) et d’utiliser la contrainte AssertTrue pour vérifier son retour…

Je ne connais pas cette API, les résultats sont checkés à l’appel de la fonction annotée ?

Édité par lthms

Merida is so cool · “Now that I have built my very own hammer, nothing looks like a nail anymore. ”

+1 -0
Auteur du sujet

Juste pour être sur, ce que tu demandes, c’est comment utiliser l’API javax.validation.constraints pour ajouter cette contrainte ?

En effet.

Je ne connais pas cette API, les résultats sont checkés à l’appel de la fonction annotée ?

je continue mes recherches et il semblerait, en effet que l’utilisation d’annotation sur une fonction soit possible, j’attends néanmoins qu’une personne qui a plus l’habitude réponde. Mais merci pour la piste lthms :)

+0 -0

Pas de souci, c’est normal. J’ai regardé rapidement sur Github, je n’ai pas trouvé d’exemples concrets qui utilisent l’approche naïve que je propose, mais je n’ai pas non plus beaucoup cherché.

Merida is so cool · “Now that I have built my very own hammer, nothing looks like a nail anymore. ”

+0 -0

Tu t’en sors comment du coup ? Tu appelles la fonction de vérification à la fin du constructeur ?

Merida is so cool · “Now that I have built my very own hammer, nothing looks like a nail anymore. ”

+0 -0
Auteur du sujet

ça donne quelque chose comme ça (j’ai enlevé les fonctions qui servent à rien)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class AnalysisInput {
    @ValidUrl(message = "Url is not valid.")
    @NotNull(message = "Url must be set.")
    @Size(min=4)
    private String url;
    private String document;
    private List<TokenInput> token;

    public boolean hasDocument() {
        return document != null && !"".equals(document);
    }

    public boolean hasToken() {
        return !hasDocument() && !token.isEmpty();
    }

    @AssertTrue(message = "You need at least a document or a list of tokens.")
    public boolean hasEnoughData(){
        return hasDocument() || hasToken();
    }
}
+0 -0
Auteur du sujet

Bon, en fait ça marchait pas vraiment, néanmoins j’ai trouvé la solution :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@DocumentOrToken
public class AnalysisInput implements DocumentContainerEntity{
    @ValidUrl(message = "You need at least a document or a list of tokens.")
    @NotNull(message = "Url must be set.")
    @Size(min=4)
    private String url;
    private String document;
    private List<TokenInput> tokens;

    public AnalysisInput() {
        this(null, null, null);
    }

    public AnalysisInput(String url, String document, List<TokenInput> token) {
        this.url = url;
        this.document = document;
        this.tokens = token;
    }

    public String getUrl() {
        return url;
    }

    @Override
    public boolean hasDocument() {
        return document != null && !"".equals(document);
    }
    @Override
    public boolean hasToken() {
        return tokens != null && !tokens.isEmpty();
    }
    @Override
    public boolean hasEnoughData(){
        return hasDocument() || hasToken();
    }
}

L’interface m’oblige simplement à avoir un "hasToken", "hasDocument" et "hasEnoughData".

Ensuite je crée l’annoation :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {ValidContentConstraintValidator.class}
)
public @interface DocumentOrToken {
    String message() default "${constraint.validation.document_or_token_needed}";
    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

pour terminer par le validateur en lui-même :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class ValidContentConstraintValidator implements ConstraintValidator<DocumentOrToken, DocumentContainerEntity> {
    @Override
    public void initialize(DocumentOrToken documentOrToken) {
        // Nothing to do
    }

    @Override
    public boolean isValid(DocumentContainerEntity documentContainerEntity, ConstraintValidatorContext constraintValidatorContext) {
        return documentContainerEntity.hasEnoughData();
    }
}
+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte