JSR 303 Validation, if one field equals something, then these other fields must not be null

I want to do a little custom validation using JSR-303 javax.validation .

I have a field. And if a certain value is entered in this field, I want to require that several other fields are not null .

I'm trying to figure it out. Not sure what I would call this to help find an explanation.

Any help would be greatly appreciated. I am new to this.

I'm currently thinking about user restrictions. But I'm not sure how to check the value of the dependent field from the annotation. Basically, I'm not sure how to access the panel object from the 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; } } } 

This is panel.status.getValue(); gives me problems .. not sure how to do this.

+45
java validation bean-validation
Feb 14 '12 at 21:30
source share
4 answers

In this case, I suggest writing a special validator that will check at the class level (so that we can access the fields of the object) that one field is required only if the other field has a specific value. Note that you must write a generic validator that gets 2 field names and only works with these two fields. To require more than one field, you must add this validator for each field.

Use the following code as an idea (I have not tested it).

  • Verification Interface

     /** * Validates that field {@code dependFieldName} is not null if * field {@code fieldName} has value {@code fieldValue}. **/ @Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Constraint(validatedBy = NotNullIfAnotherFieldHasValueValidator.class) @Documented public @interface NotNullIfAnotherFieldHasValue { String fieldName(); String fieldValue(); String dependFieldName(); String message() default "{NotNullIfAnotherFieldHasValue.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; @Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Documented @interface List { NotNullIfAnotherFieldHasValue[] value(); } } 
  • Validator implementation

     /** * Implementation of {@link NotNullIfAnotherFieldHasValue} validator. **/ public class NotNullIfAnotherFieldHasValueValidator implements ConstraintValidator<NotNullIfAnotherFieldHasValue, Object> { private String fieldName; private String expectedFieldValue; private String dependFieldName; @Override public void initialize(NotNullIfAnotherFieldHasValue annotation) { fieldName = annotation.fieldName(); expectedFieldValue = annotation.fieldValue(); dependFieldName = annotation.dependFieldName(); } @Override public boolean isValid(Object value, ConstraintValidatorContext ctx) { if (value == null) { return true; } try { String fieldValue = BeanUtils.getProperty(value, fieldName); String dependFieldValue = BeanUtils.getProperty(value, dependFieldName); if (expectedFieldValue.equals(fieldValue) && dependFieldValue == null) { ctx.disableDefaultConstraintViolation(); ctx.buildConstraintViolationWithTemplate(ctx.getDefaultConstraintMessageTemplate()) .addNode(dependFieldName) .addConstraintViolation(); return false; } } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { throw new RuntimeException(ex); } return true; } } 
  • Validator Example

     @NotNullIfAnotherFieldHasValue.List({ @NotNullIfAnotherFieldHasValue( fieldName = "status", fieldValue = "Canceled", dependFieldName = "fieldOne"), @NotNullIfAnotherFieldHasValue( fieldName = "status", fieldValue = "Canceled", dependFieldName = "fieldTwo") }) public class SampleBean { private String status; private String fieldOne; private String fieldTwo; // getters and setters omitted } 

Note that the validator implementation uses the BeanUtils class from the commons-beanutils , but you can also use BeanWrapperImpl from the Spring Framework .

See also this excellent answer: Cross-field Validation with Hibernate Validator (JSR 303)

+72
Feb 15
source share

Define a method that should be checked for true, and put the @AssertTrue annotation at the top of the page:

  @AssertTrue private boolean isOk() { return someField != something || otherField != null; } 

The method must begin with 'is'.

+34
Jun 10 '16 at 12:01
source share

You must use the 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 } 

See also a related question .

+7
Jan 25 '17 at 10:39 on
source share

Another approach would be to create a (secure) getter that returns an object containing all the dependent fields. Example:

 public class MyBean { protected String status; protected String name; @StatusAndSomethingValidator protected StatusAndSomething getStatusAndName() { return new StatusAndSomething(status,name); } } 

StatusAndSomethingValidator can now access StatusAndSomething.status and StatusAndSomething.something and perform a dependent check.

+3
Nov 25 '15 at 16:08
source share



All Articles