javavalidationjpacustom-validatorsjavax

Validating Optional Field


I have a following request json

{
 "ParameterA":"value",
 "ParameterB":[
  {
    "key":"",
  "value":""
  },
  {
    "key":"",
  "value":""
  }
    ]
}

I am trying to validate this json , my requirement is as such that if ParameterB is present then a list shd be present inside for sure, else ParameterB is optional.Such as if ParameterB itself only not present there shd nt be a problem.

I am looking for an java validation annotation for the same. i have used @NotNull on key and value but not able to decide what to use on ParameterB since it is the array inside which list is present

Since it has a database connectivity as well , I am using JPA and making this REST call.

I tried @NotEmpty on ParameterB but that doesnt help. I want an annotation so that if ParameterB itself is not present it shd nt affect the actual flow. Following Case

{
 "ParameterA":"value"
}

any suggestion or help will be appreciated.


Solution

  • The validation your are looking for is non standard one. I don't know about the existing annotation that implements this kind of validation.

    Fortunately for you javax.validation constraints can be easily extended with custom validation rules:

    a) Create a constraint annotation

    import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Target({METHOD, FIELD, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Constraint(validatedBy = NullOrNotEmptyValidator.class)
    @Documented
    public @interface NullOrNotEmpty {
    
        String message() default "{com.mycompany.constraints.nullornotempty}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
    }
    

    b) Implement a validator

    import java.lang.reflect.Array;
    import java.util.Map;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    public class NullOrNotEmptyValidator implements ConstraintValidator<NullOrNotEmpty, Object> {
    
        @Override
        public void initialize(NullOrNotEmpty constraintAnnotation) {
        }
    
        @Override
        public boolean isValid(Object object, ConstraintValidatorContext constraintContext) {
    
            if (object == null) {
                return true;
            }
    
            final Class<?> fieldClass = object.getClass();
            if (fieldClass.isArray()) {
                return Array.getLength(object) > 0;
            }
    
            if (Iterable.class.isAssignableFrom(fieldClass)) {
                return ((Iterable) object).iterator().hasNext();
            }
    
            if (Map.class.isAssignableFrom(fieldClass)) {
                return !((Map) object).isEmpty();
            }
    
            return false;
        }
    
    }
    

    c) Define a default error message

    This step depends on validation engine you are using

    Article with examples for Hibernate Validator: Chapter 3. Creating custom constraints