Spring From the Trenches: Adding Validation to a REST API

I am a bit ashamed to admit this but until yesterday, I had no idea that I can add validation to a REST API by using the @Valid and the @RequestBody annotations.

This was not working in Spring MVC 3.0 and for some reason I had not noticed that the support for this was added in Spring MVC 3.1.

I never liked the old approach because I had to

  1. Inject the Validator and MessageSource beans to my controller so that I can validate the request and fetch the localized error messages if the validation fails.
  2. Call the validation method in every controller method which input must be validated.
  3. Move the validation logic into a common base class which is extended by the controller classes.

When I noticed that I don't have to do these things anymore, I decided to write this blog post and share my findings with all of you.

Note: If we want to use the JSR-303 backed validation with Spring Framework, we have to add a JSR-303 provider to our classpath. The example applications of this blog post use Hibernate Validator 4.2.0 which is the reference implementation of the Bean Validation API (JSR-303).

Let's start by taking a look at the DTO class used in this blog post. The source code of the CommentDTO class looks as follows:

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

public class CommentDTO {

    @NotEmpty
    @Length(max = 140)
    private String text;

	//Methods are omitted.
}

Let's move on and find out how we can add validation to a REST API with Spring MVC 3.1.

Spring MVC 3.1 Is a Good Start

We can add validation to our REST API by following these steps:

  1. Implement a controller method and ensure that its input is validated.
  2. Implement the logic which handles validation errors.

Both of the steps are described in the following subsections.

Implementing the Controller

We can implement our controller by following these steps:

  1. Create a class called CommentController and annotate this class with the @Controller annotation.
  2. Add an add() method to the CommentController class which takes the added comment as a method parameter.
  3. Annotate the method with @RequestMapping and @ResponseBody annotations.
  4. Apply the @Valid and @RequestBody annotations to the method parameter.
  5. Return the added comment.

The source code of the CommentController class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@Controller
public class CommentController {

    @RequestMapping(value = "/api/comment", method = RequestMethod.POST)
    @ResponseBody
    public CommentDTO add(@Valid @RequestBody CommentDTO comment) {
        return comment;
    }
}

We have now added a new method to our controller and added validation to it. When the validation fails, the MethodArgumentNotValidException is thrown. Let's find out how we can return a meaningful response to the user of our API when the validation fails.

Handling Validation Errors

We can implement the logic which handles the validation errors by following these steps:

  1. Implement the data transfer objects which contains the information returned to the user of our REST API.
  2. Implement the exception handler method.

These steps are described with more details in the following.

Creating the Data Transfer Objects

First, we have to create the data transfer objects which contains the information returned to the user of our REST API. We can do this by following these steps:

  1. Create a DTO which contains the information of a single validation error.
  2. Create a DTO which wraps those validation errors together.

Let's get started.

The source code of the first DTO looks as follows:

public class FieldErrorDTO {

    private String field;

    private String message;

    public FieldErrorDTO(String field, String message) {
        this.field = field;
        this.message = message;
    }

	//Getters are omitted.
}

The implementation of the second DTO is rather simple. It contains a list of FieldErrorDTO objects and a method which is used to add new field errors to the list. The source code of the ValidationErrorDTO looks as follows:

import java.util.ArrayList;
import java.util.List;

public class ValidationErrorDTO {

    private List<FieldErrorDTO> fieldErrors = new ArrayList<>();

    public ValidationErrorDTO() {

    }

    public void addFieldError(String path, String message) {
        FieldErrorDTO error = new FieldErrorDTO(path, message);
        fieldErrors.add(error);
    }

   	//Getter is omitted.
}

The following listing provides an example Json document which is send back to the user of our API when the validation fails:

{
	"fieldErrors":[
		{
			"field":"text",
			"message":"error message"
		}
	]
}

Let's see how we can implement the exception handler method which creates a new ValidationErrorDTO object and returns created object.

Implementing the Exception Handler Method

We can add the exception handler method to our controller by following these steps:

  1. Add a MessageSource field to the CommentController class. The message source is used to fetch localized error message for validation errors.
  2. Inject the MessageSource bean by using constructor injection.
  3. Add a processValidationError() method to the CommentController class. This method returns ValidationErrorDTO object and takes a MethodArgumentNotValidException object as a method parameter.
  4. Annotate the method with the @ExceptionHandler annotation and ensure that the method is called when the MethodArgumentNotValidException is thrown.
  5. Annotate the method with the @ResponseStatus annotation and ensure that the HTTP status code 400 (bad request) is returned.
  6. Annotate the method with the @ResponseBody annotation.
  7. Implement the method.

Let's take a closer look at the implementation of the processValidationError() method. We can implement this method by following these steps:

  1. Get a list of FieldError objects and process them.
  2. Process the field errors one field error at the time.
  3. Try to resolve a localized error message by calling the getMessage() method of the MessageSource interface, and pass the processed field error and the current locale as method parameters.
  4. Return the resolved error message. If the error message is not found from the properties file, return the most accurate field error code.
  5. Add a new field error by calling the addFieldError() method of the ValidationErrorDTO class. Pass the name of the field and the resolved error message as method parameters.
  6. Return the created ValidationErrorDTO object after each field error has been processed.

The source code of the CommentController class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Locale;

@Controller
public class CommentController {

    private MessageSource messageSource;

    @Autowired
    public CommentController(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

	//The add() method is omitted.

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();

        return processFieldErrors(fieldErrors);
    }

    private ValidationErrorDTO processFieldErrors(List<FieldError> fieldErrors) {
        ValidationErrorDTO dto = new ValidationErrorDTO();

        for (FieldError fieldError: fieldErrors) {
            String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);
            dto.addFieldError(fieldError.getField(), localizedErrorMessage);
        }

        return dto;
    }

    private String resolveLocalizedErrorMessage(FieldError fieldError) {
        Locale currentLocale =  LocaleContextHolder.getLocale();
        String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);

        //If the message was not found, return the most accurate field error code instead.
        //You can remove this check if you prefer to get the default error message.
        if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {
            String[] fieldErrorCodes = fieldError.getCodes();
            localizedErrorMessage = fieldErrorCodes[0];
        }

        return localizedErrorMessage;
    }
}

That is it. Let's spend a moment to evaluate what we have just done.

We Are Almost There

We have now added validation to our REST API with Spring MVC 3.1. This implementation has one major benefit over the old approach:

We can trigger the validation process by using the @Valid annotation.

However, the methods annotated with the @ExceptionHandler annotation will be triggered only when the configured exception is thrown from the controller class which contains the exception handler method. This means that if our application has more than one controller, we have to create a common base class for our controllers and move the logic which handles the validation errors to that class. This might not sound like a big deal but we should prefer composition over inheritance.

Spring MVC 3.2 provides the tools which we can use to remove the need of inheritance from our controllers. Let's move on and find out how this is done.

Spring MVC 3.2 to the Rescue

Spring MVC 3.2 introduced a new @ControllerAdvice annotation which we can use to implement an exception handler component that processes the exceptions thrown by our controllers. We can implement this component by following these steps:

  1. Remove the logic which handles validation errors from the CommentController class.
  2. Create a new exception handler class and move the logic which processes validation errors to the created class.

These steps are explained with more details in the following subsections.

Removing Exception Handling Logic from Our Controller

We can remove the exception handling logic from our controller by following these steps:

  1. Remove the MessageSource field from the CommentController class.
  2. Remove the constructor from our controller class.
  3. Remove the processValidationError() method and the private methods from our controller class.

The source code of the CommentController class looks as follows:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@Controller
public class CommentController {

    @RequestMapping(value = "/api/comment", method = RequestMethod.POST)
    @ResponseBody
    public CommentDTO add(@Valid @RequestBody CommentDTO comment) {
        return comment;
    }
}

Our is next step is to create the exception handler component. Let's see how this is done.

Creating the Exception Handler Component

We can create the exception handler component by following these steps:

  1. Create a class called RestErrorHandler and annotate it with the @ControllerAdvice annotation.
  2. Add a MessageSource field to the RestErrorHandler class.
  3. Inject the MessageSource bean by using constructor injection.
  4. Add the processValidationError() method and the required private methods to the RestErrorHandler class.

The source code of the RestErrorHandler class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;
import java.util.Locale;

@ControllerAdvice
public class RestErrorHandler {

    private MessageSource messageSource;

    @Autowired
    public RestErrorHandler(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();

        return processFieldErrors(fieldErrors);
    }

    private ValidationErrorDTO processFieldErrors(List<FieldError> fieldErrors) {
        ValidationErrorDTO dto = new ValidationErrorDTO();

        for (FieldError fieldError: fieldErrors) {
            String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);
            dto.addFieldError(fieldError.getField(), localizedErrorMessage);
        }

        return dto;
    }

    private String resolveLocalizedErrorMessage(FieldError fieldError) {
        Locale currentLocale =  LocaleContextHolder.getLocale();
        String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);

        //If the message was not found, return the most accurate field error code instead.
        //You can remove this check if you prefer to get the default error message.
        if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {
            String[] fieldErrorCodes = fieldError.getCodes();
            localizedErrorMessage = fieldErrorCodes[0];
        }

        return localizedErrorMessage;
    }
}

We Are Finally There

Thanks to Spring MVC 3.2, we have now implemented an elegant solution where the validation is triggered by the @Valid annotation, and the exception handling logic is moved to a separate class. I think that we can call it a day and enjoy the results of our work.

Summary

This blog post has taught us that

  • If we want to add validation to a REST API when we are using Spring 3.0, we have to implement the validation logic ourself.
  • Spring 3.1 made it possible to add validation to a REST API by using the @Valid annotation. However, we have to create a common base class which contains the exception handling logic. Each controller which requires validation must extend this base class.
  • When we are using Spring 3.2, we can trigger the validation process by using the @Valid annotation and extract the exception handling logic into a separate class.

The example application of this blog are available at Github (Spring 3.1 and Spring 3.2)

107 comments… add one
  • Marten Deinum May 26, 2013 @ 20:24

    Great post, but I believe you can make it even more simple. The FieldError is an instance of MessageCodeResolvable which you can directly pass to the MessageSource. That should save you the codes lookup and iterating over them. That only leaves you with a check if the message and code are the same.

    • Petri May 26, 2013 @ 20:31

      Marten,

      Thank you for your comment. Your suggestion is great and makes the code much cleaner. I will update the blog post and the example projects by using the approach you suggested.

      Update: I updated the example projects and the blog post. It seems that if the error message is resolved by using the String getMessage(MessageSourceResolvable resolvable, Locale locale) method of the MessageSource interface, the AbstractMessageSource class ignores the value of the useCodeAsDefaultMessage property and always returns the default message if the message is not found. I wonder if there is a way to get rid of the if clause found from the resolveLocalizedErrorMessage(FieldError fieldError, Locale locale) method. If you know a way, let me know. :)

  • JamesBond May 31, 2013 @ 21:30

    Any idea why I'm getting this exception?

    java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]

    My method is similar to your processValidationError.

    • Petri May 31, 2013 @ 21:48

      Actually I had no idea.

      Then I found this document from the secret archives of MI6.

      It seems that the IllegalStateException exception is thrown if you have more than one method which is annotated to handle the MethodArgumentNotValidException.

      • JamesBond May 31, 2013 @ 22:04

        Thanks to your reply I have found the solution. My RestErrorHandler class extended ResponseEntityExceptionHandler class which has handleMethodArgumentNotValid method, and that was causing the exception. I no longer extend ResponseEntityExceptionHandler and it's working now.

        • Petri May 31, 2013 @ 22:22

          You are welcome! Also, it is great to hear that you solved your problem.

        • Rafa Jul 10, 2013 @ 18:20

          When you extend from ResponseEntityExceptionHandler, you have already an method annotated with @ExceptionHandler and the value MethodArgumentNotValidException.

          So if you wan to have an specific behaviour for this exception and extend from ResponseEntityExceptionHandler you should override the method:

          
          @Override
          protected ResponseEntity handleMethodArgumentNotValid(
          	MethodArgumentNotValidException ex, 
          	HttpHeaders headers, 
          	HttpStatus status, 
          	WebRequest request)
          
          
          • Petri Jul 11, 2013 @ 0:04

            Rafa,

            Thanks for pointing that option out!

  • dharmendra Jul 29, 2013 @ 16:07

    Thank you for the article. It really helped me.

    • Petri Jul 29, 2013 @ 22:48

      You are welcome. I am happy to hear that this blog post was useful to you!

  • José Sep 18, 2013 @ 11:33

    This article was really helpful. What is especially great about it is that you show solutions for different Spring versions, not just the latest one.

    The comment about omitting getters confused me a bit though. I didn't include any getters and this resulted in a HttpMediaTypeNotAcceptableException exception. Maybe that's just me though.

    • Petri Sep 18, 2013 @ 13:44

      Hi José,

      I am happy to hear that this tutorial was useful to you.

      The comment which I made about omitting getter methods means that the actual code has getter methods but I left them out from the code listing as irrelevant. Do you think that I should mention this in the sample code?

      The getter methods are required because the default configuration of Jackson requires that the DTO either has public fields or public getter methods. Since I didn't want to make the fields of my DTO class public, I had to use public getter methods.

      Were you able to solve your problem (HttpMediaTypeNotAcceptableException is thrown) or do you need some help with that?

      • Alind Billore Nov 18, 2014 @ 9:48

        Oh !
        This might be the error with me, let me try adding getters.

        • Petri Nov 18, 2014 @ 20:51

          Did it solve your problem?

  • José Sep 18, 2013 @ 16:25

    I guess it doesn't harm to be more specific about the getter to avoid confusions.

    Yes, the problem was solved by adding the getters. Thank you for your answer!

  • Uzair Sep 27, 2013 @ 19:03

    Hi Petri,

    I am trying same thing with XML configuration but its not working for me. It catches all my custom exception but its not catching @valid errors. It throws bad request which I can see in my browser console.

    @ControllerAdvice
    public class BaseExceptionResolver {

    public static final Logger LOGGER = LoggerFactory.getLogger(BaseExceptionResolver.class);

    private MessageSource messageSource;

    @Autowired
    public BaseExceptionResolver(final MessageSource messageSource) {
    LOGGER.info("entering BaseExceptionResolver constructor");
    this.messageSource = messageSource;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResponseEntity handleValidationException(MethodArgumentNotValidException pe) {
    LOGGER.info("Catched MethodArgumentNotValidException ");
    return new ResponseEntity(pe.getMessage(), HttpStatus.BAD_REQUEST);
    }
    }

    • Petri Sep 27, 2013 @ 23:20

      Hi Usair,

      The both example applications (Spring 3.1 and Spring 3.2) have a working XML configuration but it is not active by default. You can switch to XML configuration by modifying the ExampleApplicationConfig class (the required modifications should be pretty obvious).

      One thing which you could do is to compare your application configuration file to the XML configuration files of the example applications. Here are direct links to the configuration files of those applications:

      By the way, what did you mean by "it throws a bad request"?

      Your exception handler method is configured to return the HTTP status code bad request when the MethodArgumentNotValidException is thrown. That explains why you see that in your browser console.

  • Uzair Sep 30, 2013 @ 11:38

    Hi Petri,

    Thanks for your quick reply. "It throws a bad request" means control is not going inside "handleValidationException" method. I saw you XML configuration files also my files are quite similar and my ControllerAdvice is working for my custom made exception but its not calling "handleValidationException" which is there to handle @Valid validations. Here is my simple controller's method

    @RequestMapping(value = "register", method = RequestMethod.POST)
    public String registerUser(@Valid UserDTO user) {
    LOGGER.info("User : "+ user.toString());
    return "user/confirm";
    }

    my DTO

    public class UserDTO implements Serializable{

    @NotNull
    @NotEmpty
    @Length(max=2)
    private String name;

    @NotNull
    private Integer age;

    public UserDTO () {

    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public Integer getAge() {
    return age;
    }

    public void setAge(Integer age) {
    this.age = age;
    }

    @Override
    public String toString() {
    return "UserDTO [name=" + name + ", age=" + age + "]";
    }
    }

    • Petri Sep 30, 2013 @ 20:55

      Are you trying to implement a REST API method or a "regular" Spring MVC controller method?

      If you are trying to implement a regular Spring MVC controller method, you have to add a @ModelAttribute annotation before the @Valid annotation and specify the name of your form object.

  • Joe Oct 27, 2013 @ 18:57

    I am fairly new to Spring and have been using you site a guide. I started off with a Spring Roo project, but removed it after getting to a point it was no longer of little value. I used the Roo project as a basic template on how to set up a Spring project. I have Rest and Spring web controllers in the same project. In addition, the REST controllers were configured by Roo. So, they use domain objects to pass between the server and the client. However, I notice you use DTOs, which I assume is not your domain objects. If this is the case, I think the DTO method might be a bit more secure. Do you have any advice on DTOs and domain objects for REST controllers? Also, can the above controller advice work with REST and web controllers in the same project or should I move my controllers to separate projects?

    • Joe Oct 27, 2013 @ 19:09

      I think have a way to use your controller advice solution without impacting my web controllers. My web controllers use @validated and the method gets the BindingResult, which I think would prevent it from throwing the exception and not make it to the controller advice. Would you agree?

    • Petri Oct 27, 2013 @ 19:42

      Hi Joe,

      About your first question:

      I use DTOs in REST controllers for two reasons:

      1. It gives me an easy way to control which information is returned to the client. If you return domain objects, all information is returned to the client by default. This can have have dramatic effects to the performance of the application and/or it can lead into a situation where you are "leaking" sensitive information to the client. You can of course override this by using Jackson annotations but this means that your code becomes a mess.
      2. I think that the clients of my API "should not be aware" of my domain model for two reasons:
        • This provides a nice separation between the API and the inner workings of my application.
        • The domain model can be a quite complex beast. When I use DTOs, I can simplify the API in a such way that it is easier to use.

      About your second question:

      The Javadoc of the of the MethodArgumentNotValidException states that that it is thrown when validation on an argument annotated with @Valid fails.

      I assume that this means that you have to change the implementation of the method annotated with the @ExceptionHandler annotation to provide different handling logic for REST and web controllers.

      I have to admit that I haven't tested this. I guess your best option is to test this yourself (by the way, this is a good idea for a blog post).

      • Joe Oct 27, 2013 @ 23:53

        Petri,

        I appreciate the quick response. I agree with your statement using the DTO. I had the same concern about using the domain model. I was afraid of someone figuring out how to navigate the object graph and do some damage. Putting in the DTOs provides a clean break. Prior to that I was using Flex JSON annotations to exclude data I wanted to share with the client, but it was getting messy.

        As for your example, I had to add jackson-core-asl and jackson-mapper-asl to my POM to get it to work. Before adding the POM changes I would get a HTTP 415. I used the the answer on StackOverflow to work out the problem.

        http://stackoverflow.com/questions/13772146/ajax-json-post-to-spring-controller-returns-http-415

        Now the code creating the the object in the REST method, but I need to test the code further for the controller advice.

        Thanks,
        Joe

  • Joe Oct 28, 2013 @ 4:31

    Petri,

    Good news! I was able to use your example with my REST controllers without impacting my web controllers. So, my existing controller advice for my web controllers works as normal. The web controller method gets the binding results and makes decisions based off if it has errors or not. Therefore, the two can coexist without any issues.

    As for a blog post, I would like to get your thoughts on DTO and domain objects. How do you handle merging DTO changes back into the domain objects? Do you create them by hand per client/server interaction? I am thinking of creating some annotations to help create DTOs automatically from the domain objects, so the validation remains in-sync, among other things. I am working a one man project after hours, so anything I can do to reduce my workload will help.

    Thanks again,
    Joe

    • Petri Oct 28, 2013 @ 20:11

      Joe,

      It is good to know that using this technique for REST controllers doesn't cause problems with "normal" controllers. Thank you for the information!

      There are a few libraries which can be used to transform model objects into DTOs and vice versa. These libraries are:

      I have personally used a forked version version of jTransfo (I should create a pull request and see if my changes are useful to others) to transform model objects into DTOs and I have been very happy with it. However, you might want to check them all out and see which one is the best fit for you.

      I transform DTOs into model objects manually because my model objects often have domain logic in them, and copying field values from DTOs bypasses this logic. Also, I try to not have any setters in domain classes (I fail in this though). However, if your domain objects do not have any logic in them, using one of the mentioned libraries is probably a good idea.

      • Joe Oct 28, 2013 @ 21:34

        Petri,

        I am glad you sent me those links! Those are going to save me a lot of time. When I get off work, I was going to create code to do what these libraries do. Now, I am going to do some research.

        Thanks for the time saver!
        Joe

        • Petri Oct 29, 2013 @ 17:30

          Hi Joe,

          you are welcome!

  • Javier Nov 9, 2013 @ 12:46

    Hi Petri,

    I use your example to build a rest service. But I don´t understand why running the tests I have the JSON response when the validation is not correct, but when I do the calls from the SoapUI I have a 400 error and without the JSON response. If the request has a JSON object @Valid then returns a normal response but when is not valid not. As I understand is doing the validation but running with Debug is not going to the Handler code.

    Do you know why? And how I could test it outside the unit tests as for example with SoapUI?

    • Petri Nov 9, 2013 @ 13:22

      Hi Javier,

      The HTTP status code 400 (Bad request) means that the request was malformed and it could not be processed. This can be a bit confusing because the handler method returns the same status code. However, since you were able to verify that the handler method was not called, I would ensure that:

      • The value of the Content-Type request header is 'application/json'
      • The field names of the JSON send in the request body matches with the field names of the DTO object.

      These are the mistakes which I have made when I have encountered this problem. Do you see any error messages on the log?

      Also, it would be helpful if you could add the invalid JSON document here so that I could debug the example application.

      About your last question:

      It should be possible to test REST APIs by using external tools as long as the request is constructed properly (although I have no experience from SoapUI).

      • Javier Nov 9, 2013 @ 13:34

        Hi Petri,

        Thanks for answer so quick. Well my RestErrorHandler is exactly as yours. The problem is that with the test the checks are right about the message and the json response. But when I call it from SoapUI but also with rest console from chrome or whatever tool I am having a 400 error.

        So as I understand if would be some error when return the object to be mapped to JSON should go to the handle error code and after throw the error but it is not happening.

        I am not sure why is happening it. Maybe I am missing some configuration but is really strange that the test check correctly but after the rest service doesn't work in the same way.

        I would check what happens with your code and if works then I should check configuration.

        Yesterday I spent around 2h trying to fix it but I failed.
        If you have any idea let me know, tonight or tomorrow if I could fix it I will let you know as well.

        Thanks,

        • Petri Nov 10, 2013 @ 17:14

          Is your controller method called when you try to call it by using REST console or SoapUI? The HTTP status code 400 can also mean that Spring didn't find a controller method which can process your request.

          If your controller method isn't called, it would be helpful to see the request mapping of your controller method.

          • Javier Nov 10, 2013 @ 21:25

            Hi Petri,

            When the Object is valid the method is working, the problem is when the object is not valid then is not handle by the HandlerController.

            I continue looking on it, is like the @EnableMVC is not working?

  • Javier Nov 10, 2013 @ 22:28

    Well I didn't find the error but should be something in configuration. So I fork your project and it works fine.

    Finally I used your project and add my files there ;)

    • Petri Nov 10, 2013 @ 22:52

      Just realized one possible cause of this problem:

      Was the error handler class in a package which is scanned by Spring (check the @ComponentScan annotation)?

      Anyway, it is good to hear that you found at least some solution for your problem!

  • GAP Nov 14, 2013 @ 16:21

    sorry I have a Exception:

    //JSON
    {
    "username" : ""
    }

    org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

    • Petri Nov 14, 2013 @ 18:20

      You could start by verifying that

      1. Your request has an a request header called 'Accept', and its value is 'application/json'.
      2. The Jackson jar files are found from the classpath.

      I hope that this answered to your question. If this doesn't solve your problem, please let me know.

  • Thomas Beer Dec 5, 2013 @ 14:13

    Hi, great tutorial.
    Eventually you may add a comment that it is required to configure your validator, e.g. as described in http://docs.spring.io/spring/docs/3.0.0.RC3/reference/html/ch05s07.html (section 5.7.4.2). I did not have configured one ... ;-)

    Best,
    Thomas

    • Petri Kainulainen Dec 5, 2013 @ 15:09

      Hi Thomas,

      I am happy to hear that you liked this tutorial!

      If you use Spring 3.1 or newer, you don't have to configure the validator bean (unless you don't want to use the default one). As long as you annotate your configuration class (class which is annotated with the @Configuration annotation) with the @EnableWebMvc annotation, or add the <mvc:annotation-driven/> element to your XML configuration file, the validator bean is configured automatically. You have to add a JSR-303 provider to your classpath though.

      If you want to get more information about this, check out the reference manual of Spring Framework 3.1. It has a really nice section which describes what happens when you enable Spring MVC.

  • Thomas Beer Dec 6, 2013 @ 22:44

    Hi Petry,
    your are absolutely right, that's exactly what I did:
    However, the reference was wrong, actually it is described in the link above in section 5.7.4.3.
    But maybe it is of interest for any other non Spring expert as me ;-)

    Best,
    Thomas

  • Ranjana Prasad Jan 20, 2014 @ 13:44

    Thanks alot man. This was really helpful.

    • Petri Jan 20, 2014 @ 18:02

      You are welcome. I am happy to hear that this tutorial was useful to you.

  • Stephane May 11, 2014 @ 20:49

    Hi Petri,
    I'm also using a ControllerAdvice annotation and my custom exceptions are triggered fine on my REST controller. Except for the MethodArgumentNotValidException one even though I use a Valid annotation in my controller. I must be missing something. I posted on Stack http://stackoverflow.com/questions/23590763/valid-hibernate-validation-in-a-spring-rest-controller in case you find the issue interesting.
    Kind Regards,
    Stephane Eybert

    • Petri May 12, 2014 @ 21:47

      Have you tried using Hibernate Validator 4.2.0.Final? Hibernate Validator 5 is the reference implementation of the bean validation API 1.1 (JSR 349) which isn't the same specification than JSR 303.

      I assume that Spring Framework 3.2 supports only JSR 303 because I couldn't find any information about the bean validation API 1.1 from its reference manual.

  • Billy May 15, 2014 @ 19:01

    Hi Petri,

    Do you know if it is possible to override @ControllerAdvice @ModelAttribute in a controller?

    Let's say I have a list of states. For 99% of my customers they will see all the states in their select box on a form. So for this scenario I created a class and annotated it with @ControllerAdvice. I then created a method that return @ResponseBody list of states and annotated it with @ModelAttribute(value="states").

    In one of my controllers I check for a path variable and if present the states field should only display a subset of the states. I tried overriding the method in the controller with the same annotation but I get the full list each time.

    I saw this article about @ControllerAdvice in Spring 4.
    http://www.javacodegeeks.com/2013/11/controlleradvice-improvements-in-spring-4.html
    Seems like you can now specify which controllers should use the @ControlelrAdvice.

    Just wondering if you had any suggestions.

    Thanks
    Billy

    • Petri May 17, 2014 @ 14:20

      Hi Billy,

      The Javadoc of the @ControllerAdvice annotation states that it is possible to configure the controller classes which are assisted by the class annotated with the @ControllerAdvice annotation.

      If I understood correctly, you can implement your requirement by following these steps:

      1. Move the controller which displays subset of states in a package which doesn't contain other controller classes.
      2. Configure the @ControllerAdvice class to assist all other controllers except the one you moved in the first step. One way to do this is to configure the packages which contains the other controller classes by setting the value of the basePackages attribute of the @ControllerAdvice annotation.

      That is it. Remember that the class which is moved to a separate package is "on its own", and it cannot rely on the functionality provided by the @ControllerAdvice class.

  • sumit sharma Jun 27, 2014 @ 13:09

    I have a very bad confusion In spring MVC I use println method in every statement of command class setter and getter method I have a home page where I have use a link to go to login page when I click on link then control forward to login page and there is only two fileld I have declared so why getter method of user name and password called 4-4 times ..pls help me out.

    • Petri Jun 28, 2014 @ 12:07

      If you used the Spring form taglib, the getters of your form object (aka command object) are called by Spring because it retrieves the values bound to each input field.

      You can get more information about forms and Spring MVC by reading a blog post titled Spring MVC Form Tutorial.

      It is hard to say why the getters of your form object are called more than once without seeing the source code of your controller and the login page. If you want, you can add these files to pastebin so that I can take a look at them.

  • Darshan Jul 11, 2014 @ 11:46

    Hi ,
    I am using Rest web service same as you and trying to add field validation same as you have mentioned here.
    I am getting successful response but when filed error comes i am getting following exception & 400 Bad request. Below only change i did because i was getting compile error. change: new ArrayList(); instead of new ArrayList();
    public class ValidationErrorDTO {
    private List fieldErrors = new ArrayList();

    14:10:37,045 ERROR [org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver] (http-/0.0.0.0:8080-1) Failed to invoke @ExceptionHandler method: public com.csam.pps.merchant.services.ValidationErrorDTO com.csam.pps.merchant.services.RestErrorHandler.processValidationError(org.springframework.web.bind.MethodArgumentNotValidException): org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:157) [spring-webmvc-3.2.8.RELEASE.jar:3.2.8.RELEASE]

    Update: I removed the non relevant part of the stacktrace - Petri

  • psr Jul 18, 2014 @ 9:29

    Hi Petri,

    I found this to be a great tutorial. Thanks a lot!

    I was able to implement the validation for POST methods when the parameter is a @RequestBody. However, I am trying to do the validations for GET methods as well for the query parameters. The validation just doesn't happen. No errors are thrown. Any idea what I might be missing in here?

    I annotated my controller class with @Validated, and my method's query param with @Range(min=1) @RequestParam xyz. Could you please help me out here?

    Thanks a lot in advance!

    • Petri Jul 18, 2014 @ 10:46

      As far as I know, it is not possible to validate individual request parameters by using the technique described in this blog post.

      Are you trying to implement a search function which validates the search conditions? If so, I would probably validate the search conditions manually in the controller method and handle "validation errors" in the error handler class (a class that is annotated with the @ControllerAdvice annotation).

      I know that this is a bit clumsy approach. If you figure out a better way to do this, I would want to hear about it!

      • psr Jul 19, 2014 @ 0:00

        Hi Petri,

        Thanks a lot for your quick response.

        What I wanted was this:
        http://techblogs4u.blogspot.com/2012/09/method-parameter-validation-in-spring-3.html
        That link helped me.

        Also, I like most of your blogs. They are really helpful.
        Are you planning to write anything on how to setup access control and authorization in spring?
        Looking forward to that.

        • Petri Jul 20, 2014 @ 0:32

          It is nice to hear that you were able to solve your problem!

          Are you planning to write anything on how to setup access control and authorization in spring?

          I haven't made any plans to write about Spring Security anytime soon. Eugen Paraschiv has written a very comprehensive Spring Security tutorial. If you want to learn more about Spring Security, you should take a look at that tutorial.

          • psr Jul 21, 2014 @ 4:00

            Thanks a lot for the link!

          • Petri Jul 21, 2014 @ 10:39

            You are welcome. I hope that the tutorial is useful to you.

  • Stephane Aug 27, 2014 @ 11:35

    Hi Petri,

    I wonder if there is a way to handle a request aiming at an unknown mapping.

    Spring doesn't seem to send an exception in that case.

    Being able to handle the "No mapping found for HTTP request with URI" would allow us to respond with a JSON payload instead of a 404 page.

    Kind Regards,

    Stephane Eybert

  • Stephane Sep 1, 2014 @ 8:48

    Hi Petri,

    I'm looking for guidelines into validating a parent admin resource (AdminResource extending the Spring ResourceSupport class) as not being empty (@NotEmpty) in a child admin module resource (AdminModuleResource extending the Spring ResourceSupport class). I understand the
    AdminResource class should also implement the Serializable interface ? Is that the way to go with Spring ResourceSupport-ed resources ? Thanks for any directions tips !

    Kind Regards,

    Stephane Eybert

    • Petri Sep 1, 2014 @ 20:52

      I assume that you are talking about Spring HATEOAS?

      I have experience from it but you should be able to validate your DTOs by using either JSR 303 or JSR 349.

      Also, the README of Spring HATEOAS doesn't state that a class that extends the ResourceSupport class must implement the Serializable interface.

      Hmmh. Maybe I didn't understand your question. If you feel this way too, let me know.

  • Alind Billore Nov 18, 2014 @ 9:32

    Hi Petri,
    I followed your blog post but stuck at a point, the controller method annotated with @ExceptionaHandler is not registered with Jackson. Can you please please help me to sort it out ?

    I have posted my detailed question here on stackoverflow.
    http://stackoverflow.com/questions/26982053/spring-3-2-exceptionhandler-responsebody-json-response-via-jackson

    Many Thanks To You !!
    Regards,
    Alind Billore

  • Shamseer Nov 27, 2014 @ 12:44

    Hi Petri,

    I found this to be a great tutorial. Thanks a lot!.

    using @Valid MyObject obj i am able to validate MyObject. is it possible to handle javax.validation.ConstraintViolation like MethodArgumentNotValidException ? here is my code

    
    public MyResponse editFields(@RequestBody final Map jsonDataMap){
    	for (Map.Entry entry : jsonDataMap.entrySet()) {
    		MyObject obj = service.getObject(jsonDataMap.get("id"));
    		PropertyAccessor myAccessor = PropertyAccessorFactory.forBeanPropertyAccess(obj);
    	}	
    	// is it possible to validate obj here ? (i am able to valiate @Valid Object obj).
    	//
    }
    
    

    Thanks in advance.

  • Lukasz Feb 26, 2015 @ 14:27

    I just thinking its possible to change message code to hibernate validation code , for example now in your example you have got :
    NotEmpty.commentDTO.text=Text cannot be empty.
    Length.commentDTO.text=The maximum length of text is {1} characters.

    And it's ok but i want to implement strategy that when code like abowe is not visible then i am using hibernate validation :
    javax.validation.constraints.NotNull.message = may not be null
    org.hibernate.validator.constraints.Email.message = not a well-formed email address

    But now i can see any code (javax.validation.constraints.NotNull.message) ?

    • Petri Mar 1, 2015 @ 10:26

      Do you want to use the Hibernate validator's default messages or just return the error code?

      If you want to use the default messages, you can simply delete the relevant messages from the src/main/resources/i18n/messages.properties file.

      If you want to return the error code, you have modify the RestErrorHandler class. To be more specific, you have to make the following changes to its processFieldErrors() method:

      1. Instead of resolving the localized error message for each field error, you have to resolve the returned error code.
      2. Call the the addFieldError() method of the ValidationErrorDTO class and pass the field name and error code as method parameters.

      I hope that this answered to your question.

      • Nitish Jul 30, 2019 @ 19:45

        how to test this?

        • Petri Jul 30, 2019 @ 19:58

          Hi,

          If you want to write tests (either unit or integration tests) for your validation logic, you can use the Spring MVC Test framework. Unfortunately, my Spring MVC Test tutorial is a bit outdated and I should update it at some point. That being said, you should take a look at the example application of this blog post because it has some unit tests for the validation logic.

          If you have any additional questions, don't hesitate to ask them.

  • Ben Li Jun 30, 2015 @ 23:04

    First, Thanks for the great article. The example you provide work extremely well.
    I have a question regarding the rest validation.

    I have a model contains the following field.

    
    @Table
    @Entity(name = "CLIENT_ACCOUNTS")
    @JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@id")
    public class ClientAccount implements Serializable {
        private static final long serialVersionUID = -7844111354345609675L;
    
        @Id
        @Column(name = "CLIENT_ACCOUNT_ID")
        private Integer clientAccountId;
        @Column(name = "LOGON_NAME")
        @NotEmpty
        private String logonName;
        @Column(name = "PASSWORD")
        @NotEmpty
        private String password;
        @Transient
        @NotEmpty
        private String confirmPassword;
        @NotEmpty
        @Column(name = "DISPLAY_NAME")
        private String displayName;
        @Column(name = "ACCOUNT_STATUS")
        private Integer accountStatusCode;
        @Column(name = "LAST_UPDATE_DATE")
        private Date lastUpdate;
        @JoinColumn(name = "LAST_UPDATE_BY")
        @OneToOne
        private ClientAccount lastUpdatedBy;
        @Column(name = "PASSWORD_EXPIRY_DATE")
        private Date passwordExpiry;
        @Type(type = "com.test.core.hibernate.type.ValueLabelType",
    		parameters = {
    			@Parameter(name = "enumClassName", 
    			value = "com.test.common.Constants$AccountType")
    		}
        )
        @Column(name = "ACCOUNT_TYPE")
        private AccountType accountType;
        @OneToMany(mappedBy = "clientAccount")
        @JsonBackReference
        private Set clientAccesses;
    }
    
    

    and my JSON model is the subset of the Model as the following.

    
    {
        "clientAccountId": null,
        "displayName": null,
        "accountStatus": 0,
        "logonName": null,
        "password": null,
        "confirmPassword": null
    }
    
    

    my endpoint as the following

    
    @RestController
    ...
    //TODO : add security
    @RequestMapping(value="/save", method=RequestMethod.POST)
    public ClientAccountDto save(@RequestParam("wuid") WebUser webUser, 
    							 @Valid ClientAccountDto clientAccount) {
    }
    
    

    if the fields in the JSON contains the values, it works.

    if the validation failed, it returns http 400, but the responseJSON field in the response object is not set anything. the RestErrorHandler class is not called.

    if I modify the JAVA model that maps to JSON model and if the validation failed. the RestErrorHandler is call and the response.responseJSON contains the validation error message.

    My question is, is there a way to validate subset of the fields in a model?

    Thanks,

    • Petri Jun 30, 2015 @ 23:36

      Hi,

      thank you for your kind words. I really appreciate them.

      My question is, is there a way to validate subset of the fields in a model?

      Yes. You can use validation groups. You have to make the following changes to your code:

      1. Replace the @Valid annotation with the @Validated annotation and specify the used validation group(s).
      2. Add the validation group(s) to the constraint annotations. The StackOverflow question titled: Bean Validation Groups - Understanding it correctly explains how these groups works.

      However, I am not sure if this will help you to solve your problem because you mentioned that the RestErrorHandler is not called if the validation fails (if you don't modify the ClientAccount class).

      What did you mean by this, and what kind of changes do you have to do to the ClientAccount class?

  • Sandy Dec 8, 2015 @ 17:49

    Hi ,
    Can you please help me with the date validator i need to check from date is not greater then to date.
    how can i create it with the help of spring rest validator .

    • Anonymous Dec 8, 2015 @ 17:53

      this is my method which m calling from my controller
      DateValidator.validate(PageFilters pageFilters); it has 2 parameters which m passing from my controller to DateValidator class
      String fromDate = pageFilters.getFilterByAsString("fromDate");
      String toDate = pageFilters.getFilterByAsString("toDate");

      • Petri Dec 9, 2015 @ 22:34

        Hi,

        Are you trying to validate the field value of a "form" object or a single request parameter?

        If you are validating the field value of a "form" object, you have to create a custom validation constraint and annotate the relevant field with the constraint annotation. The reference manual of Hibernate Validator describes how you can do this.

        If you are validating a single request parameter, you need to add the validation logic into your controller method.

  • Gopal Mar 16, 2016 @ 16:08

    Hi I am not able to get the JSON response of ValidationErrorDTO for BAD REQUEST at my Jersey Client when I call ClientResponse.getEntity(String.class)

    But it works fine if I send header for XML response and I am getting the error response in XML properly. Can you throw some light on what might be the problem ?

    • Petri Mar 19, 2016 @ 18:28

      Hi,

      I haven't personally run into this problem, and that is why it's a bit hard to say what could be wrong. That being said, can you debug the backend and see if the error handler component is invoked when the problem occurs? Also, do you set the accept header when you face this problem?

  • Anaice Apr 2, 2016 @ 1:11

    Hi Petri.

    Your website is fantastic, it's becoming a reference to me in Spring/FunOfProgrammingWithJavaAgain World. =)
    I have some doubts about good practices and it would be very enriching to know your opinion about it.

    I'm structuring an application that has several sub-modules:

    1) myapp-commons ( utilities , logging , etc. ) JAR
    2) myapp-entity ( jpa entities, uses lombok ) JAR
    4) myapp-persistence ( repositories ) JAR
    5) myapp-service (service layer with business logic. May trigger my custom exceptions : TechnicalException, BusinessException, ValidationException and EntityNotFoundException) JAR
    6) myapp-wsrest (rest controllers, custom rest exceptions, mapstruct library to map entity resource. Catch my service layer and triggers exceptions NotFound , BadRequest and InternalServerError wrappers responses) WAR
    7) myapp-resource (DTO 's returned by rest layer, uses lombok) JAR

    first one)
    Now I'm adding Bean Validation API features. I saw that you are using the api in the REST layer. It seems to me that the best place to validate fields would not be in the service layer, after all I think the REST layer should be only a translator for the Rest API to the service layer, not worrying about details of service layer responsibility. I wonder what you think about it, what is your opinion?

    second)
    If I wanted to include these validations in the service layer @Valid the notes could be used ? Because in practical terms Spring MVC throws MethodArgumentNotValidException that can be handled to customize the validation messages in each bean field. But how to use @Valid in a common java class ( @Service ) ? There is an exception thrown by Spring?

    third one)
    Do you think Spring Data REST is a good development practice , ie use repositories with @RepositoryRestResource and expose the entities directly (without DTO, or just using @Projections)? Business rules would be in classes with @RepositoryEventHandler ( beforeSave , beforeCreate , etc. ) ? Do you have any experience to share using this approach ? ( OFF: Spring Data REST would be an interesting topic for a second edition of your book =D , by the way I will buy it soon )

    Sorry so many questions, but your opinion is very welcome!

    Thanks.

    • Petri Apr 4, 2016 @ 20:47

      Hi Anaice,

      I’m structuring an application that has several sub-modules

      I know that you didn't ask feedback about your architecture, but I think that you should read an excellent blog post titled: Whoops! Where did my architecture go.

      Now I’m adding Bean Validation API features. I saw that you are using the api in the REST layer. It seems to me that the best place to validate fields would not be in the service layer, after all I think the REST layer should be only a translator for the Rest API to the service layer, not worrying about details of service layer responsibility. I wonder what you think about it, what is your opinion?

      I think that the web layer must ensure that sane input data is provided to the service layer. However, it shouldn't enforce any business rules. This logic belongs either to the service layer or to the domain model.

      If I wanted to include these validations in the service layer @Valid the notes could be used ? Because in practical terms Spring MVC throws MethodArgumentNotValidException that can be handled to customize the validation messages in each bean field. But how to use @Valid in a common java class ( @Service ) ? There is an exception thrown by Spring?

      Check out this StackOverflow question. It describes how you can use the @Validated annotation in the service layer (I know that this doesn't use the @Valid annotation). However, I wouldn't use it in the service layer because I want to throw specific exceptions instead of the MethodArgumentNotValidException. This way I can register custom error handler methods that deal with exceptions thrown by my business logic.

      Do you think Spring Data REST is a good development practice , ie use repositories with @RepositoryRestResource and expose the entities directly (without DTO, or just using @Projections)? Business rules would be in classes with @RepositoryEventHandler ( beforeSave , beforeCreate , etc. ) ? Do you have any experience to share using this approach ?

      I have never personally used Spring Data REST so I cannot give you any feedback that is based on experience. However, if you are implementing a simple CRUD application that doesn't have complicated business logic, using it might be a viable option (it can save you a lot of time). Also, remember that can use it for certain parts of your application and implement the rest by using the "normal" approach.

  • caytekin Oct 11, 2016 @ 16:20

    Great! Thanks very much; the solution you proposed worked like a breeze for my validation. It is very clearly written and the code works as is. My compliments.

    • Petri Oct 11, 2016 @ 19:55

      Thank you for your kinds words. I really appreciate them. Also, it was nice to hear that this post was useful to you.

  • yuxh Apr 20, 2017 @ 10:04

    hi Petri,
    your article always easy to look through, but I have two question:
    1. is is best to use bean(dto here) as request body? so I have to create many dto for many different request situation?
    2. some legacy code just use @RequestParam , so is there any better way than writing validation code in controller method?

    • Petri Apr 24, 2017 @ 20:44

      Hi,

      Thank you for your kind words. I really appreciate them!

      is is best to use bean(dto here) as request body? so I have to create many dto for many different request situation?

      Yes. I know that writing DTOs takes some time, but I also think that DTOs make your code a bit easier to read and less error-prone.

      some legacy code just use @RequestParam , so is there any better way than writing validation code in controller method?

      No. If you want to implement a "proper" validation for request parameters, you have to add the validation logic to the controller method.

      If you have any additional questions, don't hesitate to ask them!

      • yuxh Apr 25, 2017 @ 9:11

        Petri ,thank you for your quick reply .
        1、but I think it's a little silly to write DTO for less than three parameter or just add property like pageNo and pageSize to create another DTO.
        2、 I add a method in RestErrorHandler to catch ConstraintViolationException for validating
        @RequestParam.
        BTW, I found spring boot has released 1.5.3 ,the test method seems change a lot ,I really love to see your new blog about this.

        • Petri Apr 25, 2017 @ 12:17

          Hi,

          But I think it’s a little silly to write DTO for less than three parameter or just add property like pageNo and pageSize to create another DTO.

          If you want to send the information to your controller by using request parameters, it makes no sense to use a DTO because Spring MVC cannot populate it (unless you write custom code). That being said, if you want to send the information in the request body, you have to use a DTO (the number of properties doesn't matter) because Spring MVC "forces" you to use it (you can actually use a Map as well but that is an horrible idea).

          Also, if you want to pass pagination information to your controller method and you are using Spring Data JPA, you should use its web pagination support (check out this blog post for more details about this).

          BTW, I found spring boot has released 1.5.3 ,the test method seems change a lot ,I really love to see your new blog about this.

          I cover this topic on my Test With Spring course. I will probably write something about it on my blog as well, but the truth is that I have to finish the course before I have time to write technical blog posts to this blog.

          • yuxh Apr 26, 2017 @ 12:14

            sorry,Petri ,I don't get your point. I must confuse something . I think @RequestParam and @RequestBody can replace eachother in REST situation, cann't they?
            In what situation should I use @RequestParam annotation?

  • Rosy Sep 11, 2017 @ 21:03

    What is the best way to validate JSON fields against database.

    • Petri Sep 11, 2017 @ 21:56

      Could you provide a bit more information about your use case? It's impossible to give you any advice because I don't know what you want to do.

  • Francesco Giusto Oct 25, 2017 @ 17:48

    Thanks for your post Petri, it was helpful and inspiring

    • Petri Oct 26, 2017 @ 12:06

      You are welcome!

  • Krishna Jul 26, 2019 @ 17:00

    Great post regarding the annotation based validations in Controller Advise. This helped me to write desired response for various HTTP status codes. Kudos Petri.

    • Petri Jul 26, 2019 @ 22:31

      Thank you for your kind words. I really appreciate them!

  • Pri May 10, 2021 @ 20:30

    My Request Body works as you have shown above but the same way when I try to add @Valid to ModelAttribute it does not work since it is not throwing : MethodArgumentNotValidException

  • Bandita Pradhan Jul 22, 2021 @ 19:52

    I put the exact code but somehow it is not entering processValidationError method. I can see the log saying , it is throwing MethodArgumentNotValidException. What is the reason it is not entering into RestErrorHandler's processValidationError method.

    Thanks,
    Bandita

    • Bandita Pradhan Jul 22, 2021 @ 20:04

      Here is my Code.

      Controller Class :

      @RestController
      @Validated
      @RequestMapping(IomCommonUriPath.IOM_BASE_URI)
      public class EprofileResource {
      private static final Logger LOGGER = LoggerFactory.getLogger(EprofileResource.class);

      private final IomServiceFacade eprofileServiceFacadeImpl;

      public EprofileResource(@Autowired IomServiceFacade eprofileServiceFacadeImpl) {
      this.eprofileServiceFacadeImpl = eprofileServiceFacadeImpl;
      }

      @PostMapping(value = "/eprofile",
      consumes = MediaType.APPLICATION_JSON_VALUE,
      produces = MediaType.APPLICATION_JSON_VALUE)
      @ResponseBody
      public IomResponseDTO callEprofile(@Valid @RequestBody ModifyApplicationRequest request) {
      LOGGER.info("[{}]-[EPRO_MS][CUSTOMER_PROFILE]-[e73c4030-b3c6-4caa-9737-51e63e668a9c] starting EPRO_MS callEprofile", request.getOrderId());
      IomResponseDTO response = null;

      try {
      response = eprofileServiceFacadeImpl.mapServiceCall(request);
      LOGGER.info("[{}]-[EPRO_MS][CUSTOMER_PROFILE]-[269de1fb-0ab3-4b5a-9a31-9546a764a1b6] Epro was process successfully", request.getOrderId());
      } catch (Exception e) { // NO SONAR
      LOGGER.error("[{}]-[EPRO_MS][CUSTOMER_PROFILE]-[0534e9a5-c1e4-446c-bb80-974dfeb00696] Error: {}",request.getOrderId(), e.getMessage());
      response = new IomResponseDTO();
      response.setStatus(IomServiceStatus.FAILED.getStatus());
      response.setErrorMessage(e.getMessage());
      }

      LOGGER.info("[{}]-[EPRO_MS][CUSTOMER_PROFILE]-[2a3b45bf-3416-4272-ae0e-134ea16187ce] leaving EPRO_MS callEprofile", request.getOrderId());
      return response;
      }

      Here is ValidationErrorHandler

      @ControllerAdvice
      public class ValidationErrorHandler {

      private static final Logger LOGGER = LoggerFactory.getLogger(ValidationErrorHandler.class);

      private MessageSource messageSource;

      @Autowired
      public ValidationErrorHandler(MessageSource messageSource) {
      this.messageSource = messageSource;
      }

      @ExceptionHandler(MethodArgumentNotValidException.class)
      @ResponseStatus(HttpStatus.BAD_REQUEST)
      @ResponseBody
      public ValidationErrorDTO processValidationError(MethodArgumentNotValidException ex) {
      LOGGER.info("In processValidationError... " );
      BindingResult result = ex.getBindingResult();
      List fieldErrors = result.getFieldErrors();
      LOGGER.info("fieldErrors =" + fieldErrors.toString() );
      return processFieldErrors(fieldErrors);
      }

      private ValidationErrorDTO processFieldErrors(List fieldErrors) {
      LOGGER.info("In processFieldErrors ");
      ValidationErrorDTO dto = new ValidationErrorDTO();
      for (FieldError fieldError : fieldErrors) {
      String localizedErrorMessage = resolveLocalizedErrorMessage(fieldError);
      dto.addFieldError(fieldError.getCode(), localizedErrorMessage );
      }
      return dto;
      }

      private String resolveLocalizedErrorMessage(FieldError fieldError) {
      LOGGER.info("In resolveLocalizedErrorMessage...");
      Locale currentLocale = LocaleContextHolder.getLocale();
      String localizedErrorMessage = messageSource.getMessage(fieldError, currentLocale);
      if (localizedErrorMessage.equals(fieldError.getDefaultMessage())) {
      String[] fieldErrorCodes = fieldError.getCodes();
      localizedErrorMessage = fieldErrorCodes[0];
      LOGGER.info("localizedErrorMessage =" + localizedErrorMessage);
      }
      return localizedErrorMessage;
      }

      }

      Here is ValidationErrorDTO class
      public class ValidationErrorDTO {
      private List fieldErrors = new ArrayList();

      public void addFieldError(String errorCode, String errorMessage) {
      for ( IomResponseDTO fieldError : fieldErrors) {
      fieldError.setErrorCode(errorCode);
      fieldError.setErrorMessage(errorMessage);
      fieldErrors.add(fieldError);
      }
      }
      }

      • Bandita Pradhan Jul 23, 2021 @ 1:01

        I am using Spring Boot 2.1.7.RELEASE . Not sure version cause any issue or not .

        • Petri Jul 24, 2021 @ 11:30

          Hi,

          One possible reason for this behavior is that the ValidationErrorHandler class isn't found by the Spring container. Check that:

          • Your component scanning configuration is correct (it includes the package of the ValidationErrorHandler class).
          • Spring creates the ValidationErrorHandler bean.
          • Bandita Pradhan Jul 27, 2021 @ 1:56

            Hi Petri,

            Thanks for reply. I can see the log creating ValidationErrorHandler bean. I put ComponentScan set to base package and it didn't work. Then I add @ControllerAdvice("com.xx.iom.eprofile") . But, it still didn't give me the response error. But, if I put ExceptionHandler in Controller class, it works.

          • Bandita Pradhan Aug 3, 2021 @ 18:53

            I changed RestController annotation to @Controller annotation in Controller Class and annotated method with @ResponseBody and it worked.

  • Dmitry Oct 16, 2021 @ 12:12

    Man thanks for the article. It was useful for me.

Leave a Reply