Estou procurando fazer uma pequena validação personalizada com JSR-303 javax.validation
.
Eu tenho um campo. E se um determinado valor for inserido neste campo, quero exigir que alguns outros campos não sejam null
.
Estou tentando descobrir isso. Não sei exatamente como chamaria isso para ajudar a encontrar uma explicação.
Qualquer ajuda seria apreciada. Eu sou muito novo nisso.
No momento, estou pensando em uma restrição personalizada. Mas não tenho certeza de como testar o valor do campo dependente de dentro da anotação. Basicamente, não tenho certeza de como acessar o objeto de painel a partir da anotação.
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;
}
}
}
É o panel.status.getValue();
que está me causando problemas ... não tenho certeza de como fazer isso.
Object
). Neste caso, você nem precisa usar reflexão para obter os valores, mas neste caso o validador se torna menos genérico 2) usoBeanWrapperImp
do Spring Framework (ou outras bibliotecas) e seugetPropertyValue()
método. Nesse caso, você poderá obter um valor comoObject
e convertê-lo em qualquer tipo de que precisar.Defina o método que deve ser validado como verdadeiro e coloque a
@AssertTrue
anotação no topo dele:@AssertTrue private boolean isOk() { return someField != something || otherField != null; }
O método deve começar com 'é'.
fonte
@AssertTrue(message="La reference doit etre un URL") public boolean isReferenceOk() { return origine!=Origine.Evolution||reference.contains("http://jira.bcaexpertise.org"); }
E isso no meu 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>
Mas dá um erro.Você deve fazer 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 }
Veja também a questão relacionada neste tópico .
fonte
getValidationGroups(MyCustomForm myCustomForm)
método. Você poderia ajudar aqui? : stackoverflow.com/questions/44520306/…Aqui está minha opinião sobre isso, tentei mantê-lo o mais simples possível.
A 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(); }
Implementação de validação:
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; }
Mensagens:
fonte
Uma abordagem diferente seria criar um getter (protegido) que retornasse um objeto contendo todos os campos dependentes. Exemplo:
public class MyBean { protected String status; protected String name; @StatusAndSomethingValidator protected StatusAndSomething getStatusAndName() { return new StatusAndSomething(status,name); } }
StatusAndSomethingValidator agora pode acessar StatusAndSomething.status e StatusAndSomething.something e fazer uma verificação dependente.
fonte
Amostra abaixo:
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"; } } }
fonte