18

I have a model class which has list of Strings. The list can either be empty or have elements in it. If it has elements, those elements can not be empty. For an example suppose I have a class called QuestionPaper which has a list of questionIds each of which is a string.

class QuestionPaper{
private List<String> questionIds;
....
}

The paper can have zero or more questions. But if it has questions, the id values can not be empty strings. I am writing a micro service using SpringBoot, Hibernate, JPA and Java. How can I do this validation. Any help is appreciated.

For an example we need to reject the following json input from a user.

{ "examId": 1, "questionIds": [ "", " ", "10103" ] }

Is there any out of the box way of achieving this, or will I have to write a custom validator for this.

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63

6 Answers6

31

Custom validation annotation shouldn't be a problem:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NotEmptyFieldsValidator.class)
public @interface NotEmptyFields {

    String message() default "List cannot contain empty fields";

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

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

}


public class NotEmptyFieldsValidator implements ConstraintValidator<NotEmptyFields, List<String>> {

    @Override
    public void initialize(NotEmptyFields notEmptyFields) {
    }

    @Override
    public boolean isValid(List<String> objects, ConstraintValidatorContext context) {
        return objects.stream().allMatch(nef -> nef != null && !nef.trim().isEmpty());
    }

}

Usage? Simple:

class QuestionPaper{

    @NotEmptyFields
    private List<String> questionIds;
    // getters and setters
}

P.S. Didn't test the logic, but I guess it's good.

Zarremgregarrok
  • 484
  • 5
  • 8
Branislav Lazic
  • 14,388
  • 8
  • 60
  • 85
  • The validation looks like it would crash on `nef==null` – Zarremgregarrok Sep 18 '18 at 16:52
  • I edit the code like below and it works perfect: @Override public boolean isValid(List objects, ConstraintValidatorContext context) { if (objects == null || objects.isEmpty()) return false; return objects.stream().allMatch(nef -> nef != null && !nef.trim().isEmpty()); } – Vickie Jack Mar 06 '20 at 09:52
  • Overengineering I guess. You can simply use the already existing annotations. – rios0rios0 Mar 10 '22 at 19:22
18

I just had similar case to solve

class QuestionPaper {

    @NotEmpty
    private List<@NotBlank String> questionIds;

    // getters and setters
}
nmgds
  • 181
  • 2
  • 3
  • It actually triggers an error 500 that can't be handled. "org.springframework.beans.NotReadablePropertyException". Example of message: "JSR-303 validated property XYZ does not have a corresponding accessor for Spring data binding - check your DataBinder's configuration (bean property versus direct field access)" – rios0rios0 Mar 10 '22 at 17:30
  • Correcting my own comment. It actually works. But, to do this answer in a proper way, you need BEFORE do this: https://stackoverflow.com/a/44064198/10746857. – rios0rios0 Mar 10 '22 at 19:21
  • It works out of the box for me with the latest Spring boot (3.0.2) with Graphql – Marthym Feb 07 '23 at 21:30
5

These might suffice the need, if it is only on null or empty space.

@NotNull, @Valid, @NotEmpty

You can check with example. Complete set of validations - JSR 303 give an idea which suits the requirement.

Vinay Veluri
  • 6,671
  • 5
  • 32
  • 56
  • 4
    I have already tried, but these are not recursively applied to the list elements, rather it is enforced to the list. Thanks for the reply though. :) – Ravindra Ranwala Sep 15 '16 at 06:33
3

If List is of Integers, then go as below

class QuestionPaper {

    @NotEmpty
    private List<@Min(0) Integer> questionIds;

    // getters and setters
}
KayV
  • 12,987
  • 11
  • 98
  • 148
1
!CollectionUtils.isEmpty(questionIds) 
   && !questionIds.stream.anyMatch(StringUtils::isEmpty())
Journeycorner
  • 2,474
  • 3
  • 19
  • 43
  • This also seems to work, List questionIds = Arrays.asList("1000", "", " "); if (!questionIds.contains(null) && !questionIds.contains("")) { System.out.println("Valid List !!!!"); } else { System.out.println("Invalid List!!!!"); } My concern is how to add this to spring validator. – Ravindra Ranwala Sep 15 '16 at 06:44
  • I am not sure whether or not Bean Validation works on references – Journeycorner Sep 15 '16 at 08:15
0

This can easily be addressed if you use

import org.apache.commons.collections.CollectionUtils;

    QuestionPaper question = new QuestionPaper();
    question.setQuestionIds(Arrays.asList("", " ", "10103"));

   if(CollectionUtils.isNotEmpty(question.getQuestionIds())) {
        // proceed
    } else {
        //throw exception or return
    }

This will check for nontnull and notempty.