4

I have a spring controller :

@RequestMapping(value = "bulk", method = RequestMethod.POST)
@ResponseBody
public APIResponse createBulkEnquiries(@Valid @RequestBody List<BulkDTO> bulkDTOs) {
    // some code 
}

It is not validating any of the bulkDTOs as @valid do not work on element of Collection directly (although BulkDTO is validatable). Also I can not wrap List in some other class (which works) like

public class ValidatableObjectsCollectionWrapper {
    @Valid
    List<BulkDTO> bulkDTOs;
}

because it will change input json format. So I need some other way around.

I also tried to make a custom validator for collection

public class CollectionValidator implements Validator {

private final SpringValidatorAdapter validator;

public CollectionValidator(SpringValidatorAdapter validator) {
    super();
    this.validator = validator;
}

@Override
public boolean supports(Class<?> clazz) {
    return Collection.class.equals(clazz);
}

@Override
public void validate(Object target, Errors errors) {

    Collection<Object> objectCollection = (Collection<Object>) target;

    for (Object object : objectCollection) {
        validator.validate(object, errors);
    }
}
}

But Don't know how to invoke or bind it on the controller param.

3
  • I think spring doesnot validate collection elements using @valid. I think you can implement custom validator where you can have your own validations by iterating or streaming through the list. Commented Jan 3, 2016 at 15:17
  • I tried it, Don't know how to invoke it (see the updated question). Commented Jan 3, 2016 at 16:34
  • IMHO this is stackoverflow.com/questions/34011892/… an elegant solution. Hope it helps. Commented Apr 22, 2016 at 9:52

2 Answers 2

6

Not sure if it's the only, or the best solution, but you can use a wrapper object, without having to change the JSON, using the @JsonValue and @JsonCreator annotations. Here is a complete example:

public class BulkDTOWrapper {

    private List<BulkDTO> bulks;

    @JsonCreator
    public BulkDTOWrapper(List<BulkDTO> bulks) {
        this.bulks = bulks;
    }

    public BulkDTOWrapper() {
    }

    @JsonValue
    public List<BulkDTO> getBulks() {
        return bulks;
    }

    public void setBulks(List<BulkDTO> bulks) {
        this.bulks = bulks;
    }

    public static void main(String[] args) throws IOException {
        BulkDTO b1 = new BulkDTO("hello");
        BulkDTO b2 = new BulkDTO("world");

        BulkDTOWrapper wrapper = new BulkDTOWrapper();
        wrapper.setBulks(Arrays.asList(b1, b2));

        ObjectMapper om = new ObjectMapper();
        String json = om.writeValueAsString(wrapper);
        System.out.println("json = " + json);

        BulkDTOWrapper wrapper2 = om.readValue(json, BulkDTOWrapper.class);
        System.out.println(wrapper2.getBulks().size());
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Nizet. Although it is not the best solution, but it may solve my problem.
2

Actually, this can be achieved using Spring Validation and JSR303.

*Expose a MethodValidationPostProcessor bean.

Annotate your controller class with @Validated (org.springframework.validation.annotation.Validated)

Use the JSR303 validation annotations on your MyEntity fields/methods.

Annotate your RequestBody argument with @Valid (you've already done this in your example).

Add an @ExceptionHandler method to handle MethodArgumentNotValidException. This can be done in the controller or in a @ControllerAdvice class.*

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.