0

I'm working with Java validation and Spring. I have several classes that need validation set up. When it comes to validating simple fields of each class, my validators work fine. However, the field for one class contains a List of two other classes I need validated, and one of those contains a list of two other classes I need validated.

I found a way to get this working, but it is a bit messy and requires (what I think) is too much extra code in my Controller. For example, I made a separate method in my validation to validate the list of Class A:

    public Errors validateClassA(ClassA classA){
        List<ClassB> classBs = classA.getScanResults().getClassesToValidate();
            for (ClassB classB : classBs) {
                Errors error = new BeanPropertyBindingResult(classB, "ClassB");
                classBValidator.validate(classB, error);
                if(error.hasErrors()){
                    return error;
                }
            }
            return null; 
        }

This works just for testing, but I don't want to pass back a null value and it seems a little bit messy. Here's the portion of my Controller using this code:

 classAValidator.validate(classA, bindingResult);
 Errors classBErrors = classAValidator.validateClassB(classA);
 if (bindingResult.hasErrors()) {
     classAValidator.logErrors(bindingResult);
     return new ResponseEntity<GenericServiceResponse<Void>>(new GenericServiceResponse<Void>(FAIL, bindingResult.toString()), HttpStatus.BAD_REQUEST);
 }
 if(classBErrors.hasErrors()){
     classAValidator.logErrors(classBErrors);
     return new ResponseEntity<GenericServiceResponse<Void>>(new GenericServiceResponse<Void>(FAIL, classBErrors.toString()), HttpStatus.BAD_REQUEST);
 }           

Feels like I'm making this more complicated than it needs to be, but I'm not sure how to approach it. From a brief glance at the documentation for the Errors class, it looks like there is some way to set nested routes for the errors, but I couldn't seem to find many examples of that so I'm not sure if it would apply in my situation. Hope all of this makes sense and thanks for any suggestions.

1 Answer 1

1

Yeah, you are making this issue more complicated that it needs to be :) You do not need to implement these functionalities by yourself - Spring does it for you.

Let's assume you have a simple DTO like the one below:

public class SomeDTO {

   public static class SomeOtherDTO {

      @NotEmpty
      private String someOtherField;

   }

   @NotNull
   private SomeOtherDTO someField;

}

and @RestController with method:

@RequestMapping(value = "/someEndpoint", method = RequestMethod.POST)
public ResponseEntity<HttpStatus> someEndpoint(@Valid @RequestBody SomeDTO dto) {
    return new ResponseEntity<>(HttpStatus.OK);
}

This is all - dto will now be validated by Spring - all you have to do is handle potential errors yourself. You can do it many different ways. My suggestion is to use @ControllerAdvice - that way you have unified approach to validation error handling across all registered @Controllers:

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception, HttpHeaders headers, HttpStatus status, WebRequest request) {
        // here you have access to the errors via exception argument - do with them whatever you want
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the response. That is how I looked into doing this at first actually, but the classes I'm working with are relatively large and from what I read, creating your own custom validator (implementing Spring's validator interface) is best for extension/readability. My issue is lying more in how I need to use one validator within another, but once I'm using the "nested" validator, I can't get those errors back to the Controller.

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.