Home > Software design >  List not honoring @NotEmpty annotation
List not honoring @NotEmpty annotation

Time:11-28

I have a list that is filled with a request body. I expect 400 BAD Request response status when No value or Null is passed in request. is working as expected when No value is being passed. But for Null, it does not throw 400. How can I make it work?

class data{

    @NotEmpty
    private List<@Valid String> values;

}

Request body 1 -> getting response status 200. This is expected.

{
  "values": [
        "randomValue"
      ]
}

Request body 2 -> getting response status 400 (VALIDATION_ERROR) . This is expected.

{
 
}

Request body 3 -> getting response status 400 (VALIDATION_ERROR) . This is expected.

{
  "values": [
        
      ]
}

Request body 4 -> getting response status 200. Expected status 400 (VALIDATION_ERROR).

{
  "values": [
        null
      ]
}

CodePudding user response:

This is because an array/list with null elements is not empty. You can handle this by defining a new custom validation for validating the list input. See an example below:

Define a new Annotation ValidList (you can name it something else too as per your liking). Note the validatedBy attribute - this is the class that will do the actual validation for the fields annotated with this annotation.

import javax.validation.Constraint;
import javax.validation.Payload;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER,         
ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = ListValidator.class)
public @interface ValidList  {
    String message() default "Array/List field cannot be null";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Define the actual validator class - validation is handled by this custom validator ListValidator (code below):

import java.util.List;
import java.util.Objects;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class ListValidator implements ConstraintValidator<ValidList, List<? extends Object>> {
    @Override
    public boolean isValid(List<? extends Object> list, 
    ConstraintValidatorContext context) {
        //NOTE: this condition will mark the list invalid even if there is a single null element present in the list (you can change it to fit your use-case)
        return !(list == null || list.isEmpty() || list.stream().anyMatch(Objects::isNull));
    }

    @Override
    public void initialize(ValidList constraintAnnotation) {}
}

Now, just use the newly created ValidList annotation on your Data class:

    public class Data {
        @ValidList
        private List<@Valid String> values;

        public List<String> getValues() {
            return values;
        }

        public void setValues(List<String> values) {
            this.values = values;
        }

        public Data() {
        }

        public Data(@NotEmpty List<@Valid String> values) {
            this.values = values;
        }

    }

CodePudding user response:

You can use the @NotNull annotation for list elements:

@NotEmpty
private List<@NotNull String> values;
  • Related