Chcę przeprowadzić małą niestandardową walidację z JSR-303 javax.validation
.
Mam pole. A jeśli w tym polu zostanie wprowadzona pewna wartość, chcę wymagać, aby kilka innych pól nie było null
.
Próbuję to rozgryźć. Nie jestem pewien, jak nazwałbym to, aby znaleźć wyjaśnienie.
Każda pomoc będzie mile widziana. Jestem w tym całkiem nowy.
W tej chwili myślę o niestandardowym ograniczeniu. Ale nie jestem pewien, jak przetestować wartość pola zależnego z poziomu adnotacji. Zasadniczo nie jestem pewien, jak uzyskać dostęp do obiektu panelu z adnotacji.
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;
}
}
}
To panel.status.getValue();
sprawia mi kłopoty… nie wiem, jak to osiągnąć.
Object
). W tym przypadku nie musisz nawet używać refleksji, aby uzyskać wartości, ale w tym przypadku walidator stanie się mniej ogólny 2) użyjBeanWrapperImp
Spring Framework (lub innych bibliotek) i jegogetPropertyValue()
metody. W takim przypadku będziesz mógł uzyskać wartość jakoObject
i rzutować na dowolny typ, którego potrzebujesz.Zdefiniuj metodę, która musi zostać zweryfikowana jako true i umieść
@AssertTrue
adnotację na jej wierzchu:@AssertTrue private boolean isOk() { return someField != something || otherField != null; }
Metoda musi zaczynać się od „jest”.
źródło
@AssertTrue(message="La reference doit etre un URL") public boolean isReferenceOk() { return origine!=Origine.Evolution||reference.contains("http://jira.bcaexpertise.org"); }
A to w moim 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>
Ale wyrzuca błąd.Powinieneś skorzystać z niestandardowych
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 }
Zobacz także powiązane pytanie na ten temat .
źródło
getValidationGroups(MyCustomForm myCustomForm)
metody. Czy mógłbyś tu pomóc? : stackoverflow.com/questions/44520306/ ...Oto moje podejście, starałem się, aby było to tak proste, jak to tylko możliwe.
Interfejs:
@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(); }
Wdrożenie walidacji:
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(); } }
Stosowanie:
@OneOf({"stateType", "modeType"}) public class OneOfValidatorTestClass { private StateType stateType; private ModeType modeType; }
Wiadomości:
źródło
Innym podejściem byłoby utworzenie (chronionego) modułu pobierającego, który zwraca obiekt zawierający wszystkie zależne pola. Przykład:
public class MyBean { protected String status; protected String name; @StatusAndSomethingValidator protected StatusAndSomething getStatusAndName() { return new StatusAndSomething(status,name); } }
StatusAndSomethingValidator może teraz uzyskać dostęp do StatusAndSomething.status i StatusAndSomething.something i dokonać zależnego sprawdzenia.
źródło
Próbka poniżej:
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"; } } }
źródło