Estoy buscando hacer una pequeña validación personalizada con JSR-303 javax.validation
.
Tengo un campo. Y si se ingresa un cierto valor en este campo, quiero requerir que algunos otros campos no lo estén null
.
Estoy tratando de resolver esto. No estoy seguro de cómo llamaría esto para ayudar a encontrar una explicación.
Cualquier ayuda sería apreciada. Soy bastante nuevo en esto.
Por el momento estoy pensando en una restricción personalizada. Pero no estoy seguro de cómo probar el valor del campo dependiente desde dentro de la anotación. Básicamente, no estoy seguro de cómo acceder al objeto del panel desde la anotación.
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;
}
}
}
Es lo panel.status.getValue();
que me está dando problemas ... no estoy seguro de cómo lograr esto.
Object
). En este caso, ni siquiera necesita usar la reflexión para obtener los valores, pero en este caso el validador se vuelve menos genérico 2) useBeanWrapperImp
de Spring Framework (u otras bibliotecas) y sugetPropertyValue()
método. En este caso, podrá obtener un valorObject
y convertir a cualquier tipo que necesite.Defina el método que debe validar como verdadero y coloque la
@AssertTrue
anotación en la parte superior:@AssertTrue private boolean isOk() { return someField != something || otherField != null; }
El método debe comenzar con 'is'.
fuente
@AssertTrue(message="La reference doit etre un URL") public boolean isReferenceOk() { return origine!=Origine.Evolution||reference.contains("http://jira.bcaexpertise.org"); }
Y esto en mi 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>
Pero arroja un error.Deberías hacer uso de custom
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 }
Consulte también la pregunta relacionada sobre este tema .
fuente
getValidationGroups(MyCustomForm myCustomForm)
método. ¿Podrías ayudarme aquí? : stackoverflow.com/questions/44520306/…Aquí está mi opinión, traté de mantenerlo lo más simple posible.
La interfaz:
@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(); }
Implementación de validación:
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(); } }
Uso:
@OneOf({"stateType", "modeType"}) public class OneOfValidatorTestClass { private StateType stateType; private ModeType modeType; }
Mensajes:
fuente
Un enfoque diferente sería crear un captador (protegido) que devuelva un objeto que contenga todos los campos dependientes. Ejemplo:
public class MyBean { protected String status; protected String name; @StatusAndSomethingValidator protected StatusAndSomething getStatusAndName() { return new StatusAndSomething(status,name); } }
StatusAndSomethingValidator ahora puede acceder a StatusAndSomething.status y StatusAndSomething.something y hacer una verificación dependiente.
fuente
Muestra a continuación:
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"; } } }
fuente