Validating Request Data — Validating In Service Layer

If you want to do validation in the service layer, which is a good practice, Spring Boot supports it very well. Instead of using the @Valid annotation in the controller, you’ll need to do it in the service, as below:

Don’t miss the class level @Validated annotation.

So, how does it work?

Spring Boot auto configures a MethodValidationPostProcessor component, which validates all method parameters that are annotated with @Valid inside all components that are annotated with @Validated. It throws a ConstraintViolationException exception in case of errors.

Our job then becomes handling the exception and translating that to a suitable error response. While we've already discussed how to handle exceptions previous section, let's now discuss how to translate a ConstraintViolationException to a suitable response body.

How to translate ConstraintViolationExceptions

Getting the validation errors

ConstraintViolationException’s getConstraintViolations() method returns the errors as a set of ConstraintViolations. So, we should transform those ConstraintViolations into a simple structure and return that in the response.

Structure to send to the client

A simple structure for returning validation errors to the client could look like this:

It's an array of error messages. Each error message has

  1. A field containing the path of the field. Nested fields can have multiple dots in them, like user.address.lane in the fifth case above. In case the error is not related to a specific field, but is a form-level global error, as in the fourth case above, field can be just the object name, null, or something unknown.
  2. A code containing the error code.
  3. A message containing an internationalized error message.

These error messages can be structured as a simple class as below:

Converting ConstraintViolations to FieldErrors

ConstraintViolation has the following attributes:

The propertyPath above is of the format methodName.objectName.fieldName. We won’t need the methodName prefix when sending it to the client. To strip it out, the code snippet below can be used:

So, in summary, the method below would convert a ConstraintViolation to a FieldError:

Using the above method, a set of ConstraintViolations can then be converted to a list of FieldErrors as below:

Look at the LemonFieldError and the DefaultExceptionHandlerControllerAdvice classes in Spring Lemon for precise details.

But how to provide custom messages, do custom validation, use validation groups etc.? Join me in the next lesson to discuss all these.