Je cherche à faire une petite validation personnalisée avec JSR-303 javax.validation
.
J'ai un champ. Et si une certaine valeur est entrée dans ce champ, je veux exiger que quelques autres champs ne le soient pas null
.
J'essaye de comprendre ça. Je ne sais pas exactement comment j'appellerais cela pour aider à trouver une explication.
Toute aide serait appréciée. Je suis assez nouveau dans ce domaine.
En ce moment, je pense à une contrainte personnalisée. Mais je ne sais pas comment tester la valeur du champ dépendant à partir de l'annotation. Fondamentalement, je ne sais pas comment accéder à l'objet panneau à partir de l'annotation.
public class StatusValidator implements ConstraintValidator<NotNull, String> {
@Override
public void initialize(NotNull constraintAnnotation) {}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ("Canceled".equals(panel.status.getValue())) {
if (value != null) {
return true;
}
} else {
return false;
}
}
}
C'est le panel.status.getValue();
qui me donne des ennuis ... je ne sais pas comment y parvenir.
Object
). Dans ce cas, vous n'avez même pas besoin d'utiliser la réflexion pour obtenir les valeurs, mais dans ce cas, le validateur devient moins générique 2) utilisezBeanWrapperImp
Spring Framework (ou d'autres bibliothèques) et sagetPropertyValue()
méthode. Dans ce cas, vous serez en mesure d'obtenir une valeur en tant queObject
et de le convertir en n'importe quel type dont vous avez besoin.Définissez la méthode qui doit valider sur true et placez l'
@AssertTrue
annotation par-dessus:@AssertTrue private boolean isOk() { return someField != something || otherField != null; }
La méthode doit commencer par «est».
la source
@AssertTrue(message="La reference doit etre un URL") public boolean isReferenceOk() { return origine!=Origine.Evolution||reference.contains("http://jira.bcaexpertise.org"); }
Et cela dans mon jsp:<th><form:label path="reference"><s:message code="reference"/></form:label></th><td><form:input path="reference" cssErrorClass="errorField"/><br/><form:errors path="isReferenceOk" cssClass="error"/></td>
Mais cela jette une erreur.Vous devez utiliser la personnalisation
DefaultGroupSequenceProvider<T>
:ConditionalValidation.java
// Marker interface public interface ConditionalValidation {}
MyCustomFormSequenceProvider.java
public class MyCustomFormSequenceProvider implements DefaultGroupSequenceProvider<MyCustomForm> { @Override public List<Class<?>> getValidationGroups(MyCustomForm myCustomForm) { List<Class<?>> sequence = new ArrayList<>(); // Apply all validation rules from ConditionalValidation group // only if someField has given value if ("some value".equals(myCustomForm.getSomeField())) { sequence.add(ConditionalValidation.class); } // Apply all validation rules from default group sequence.add(MyCustomForm.class); return sequence; } }
MyCustomForm.java
@GroupSequenceProvider(MyCustomFormSequenceProvider.class) public class MyCustomForm { private String someField; @NotEmpty(groups = ConditionalValidation.class) private String fieldTwo; @NotEmpty(groups = ConditionalValidation.class) private String fieldThree; @NotEmpty private String fieldAlwaysValidated; // getters, setters omitted }
Voir également la question connexe à ce sujet .
la source
getValidationGroups(MyCustomForm myCustomForm)
méthode. Pourriez-vous éventuellement aider ici? : stackoverflow.com/questions/44520306/…Voici mon point de vue, j'ai essayé de le garder aussi simple que possible.
L'interface:
@Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Constraint(validatedBy = OneOfValidator.class) @Documented public @interface OneOf { String message() default "{one.of.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String[] value(); }
Mise en œuvre de la validation:
public class OneOfValidator implements ConstraintValidator<OneOf, Object> { private String[] fields; @Override public void initialize(OneOf annotation) { this.fields = annotation.value(); } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(value); int matches = countNumberOfMatches(wrapper); if (matches > 1) { setValidationErrorMessage(context, "one.of.too.many.matches.message"); return false; } else if (matches == 0) { setValidationErrorMessage(context, "one.of.no.matches.message"); return false; } return true; } private int countNumberOfMatches(BeanWrapper wrapper) { int matches = 0; for (String field : fields) { Object value = wrapper.getPropertyValue(field); boolean isPresent = detectOptionalValue(value); if (value != null && isPresent) { matches++; } } return matches; } private boolean detectOptionalValue(Object value) { if (value instanceof Optional) { return ((Optional) value).isPresent(); } return true; } private void setValidationErrorMessage(ConstraintValidatorContext context, String template) { context.disableDefaultConstraintViolation(); context .buildConstraintViolationWithTemplate("{" + template + "}") .addConstraintViolation(); } }
Usage:
@OneOf({"stateType", "modeType"}) public class OneOfValidatorTestClass { private StateType stateType; private ModeType modeType; }
Messages:
la source
Une approche différente serait de créer un getter (protégé) qui retourne un objet contenant tous les champs dépendants. Exemple:
public class MyBean { protected String status; protected String name; @StatusAndSomethingValidator protected StatusAndSomething getStatusAndName() { return new StatusAndSomething(status,name); } }
StatusAndSomethingValidator peut désormais accéder à StatusAndSomething.status et StatusAndSomething.something et effectuer une vérification dépendante.
la source
Échantillon ci-dessous:
package io.quee.sample.javax; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.validation.ConstraintViolation; import javax.validation.Valid; import javax.validation.Validator; import javax.validation.constraints.Pattern; import java.util.Set; /** * Created By [**Ibrahim Al-Tamimi **](https://www.linkedin.com/in/iloom/) * Created At **Wednesday **23**, September 2020** */ @SpringBootApplication public class SampleJavaXValidation implements CommandLineRunner { private final Validator validator; public SampleJavaXValidation(Validator validator) { this.validator = validator; } public static void main(String[] args) { SpringApplication.run(SampleJavaXValidation.class, args); } @Override public void run(String... args) throws Exception { Set<ConstraintViolation<SampleDataCls>> validate = validator.validate(new SampleDataCls(SampleTypes.TYPE_A, null, null)); System.out.println(validate); } public enum SampleTypes { TYPE_A, TYPE_B; } @Valid public static class SampleDataCls { private final SampleTypes type; private final String valueA; private final String valueB; public SampleDataCls(SampleTypes type, String valueA, String valueB) { this.type = type; this.valueA = valueA; this.valueB = valueB; } public SampleTypes getType() { return type; } public String getValueA() { return valueA; } public String getValueB() { return valueB; } @Pattern(regexp = "TRUE") public String getConditionalValueA() { if (type.equals(SampleTypes.TYPE_A)) { return valueA != null ? "TRUE" : ""; } return "TRUE"; } @Pattern(regexp = "TRUE") public String getConditionalValueB() { if (type.equals(SampleTypes.TYPE_B)) { return valueB != null ? "TRUE" : ""; } return "TRUE"; } } }
la source