Automatic conversion of JSON form parameter in Spring MVC 4.0

I am trying to build a Spring MVC controller that will receive a POSTed form with a parameter in JSON format and Spring will automatically convert it to a Java object.

  • application/x-www-form-urlencoded request content type
  • The name of the parameter containing the JSON string, data.json

This is the controller:

 @Controller public class MyController { @RequestMapping(value = "/formHandler", method = RequestMethod.POST) public @ResponseBody String handleSubscription( @RequestParam("data.json") MyMessage msg) { logger.debug("id: " + msg.getId()); return "OK"; } } 

And here is what the MyMessage object looks like:

 public class MyMessage { private String id; // Getter/setter omitted for brevity } 

Perhaps unsurprisingly, placing a form with the parameter data.json = {"id": "Hello"} results in an HTTP 500 error with this exception:

 org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'MyMessage' nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [MyMessage]: no matching editors or conversion strategy found 

If I read MappingJackson2HttpMessageConverter correctly , the Jackson JSON conversion is triggered by the Content-Type application/json , which I obviously cannot use, since this is a form of POST (and I do not control the POSTing part).

Is it possible to get Spring to convert a JSON string to an instance of MyMessage, or should I just give up, read it as a String, and do the conversion myself?

+7
java json spring jackson spring-mvc
source share
2 answers

Spring calls your @RequestMapping methods with reflection. To resolve each argument that he will pass to the call, he uses the HandlerMethodArgumentResolver implementation. For @RequestParam annotated parameters, RequestParamMethodArgumentResolver used. This implementation binds the request parameter to a single object, usually a String or some type of Number .

However, your use case is slightly less common. You rarely get json as the request parameter , so I think you should think about your design , but if you have no other choice, you need to register a custom PropertyEditor , which will take care of converting the value of the json request parameter to its own type.

Registration is simple in the annotated @InitBinder method in your @Controller class

 @InitBinder public void initBinder(WebDataBinder dataBinder) { dataBinder.registerCustomEditor(MyMessage.class, new PropertyEditorSupport() { Object value; @Override public Object getValue() { return value; } @Override public void setAsText(String text) throws IllegalArgumentException { value = new Gson().fromJson((String) text, MyMessage.class); } }); } 

In this particular case, we do not need all the methods of the PropertyEditor interface, so we can use PropertyEditorSupport , which is a useful default implementation of PropertyEditor . We simply implement two methods that we take care of using the taste of the JSON parser that we want. I used Gson because it was available.

When Spring sees that it has the requested query parameter, it checks the parameter type, finds the MyMessage type MyMessage and looks for the registered PropertyEditor for this type. He will find it because we registered it, and he will use it to convert the value.

You may need to implement other PropertyEditor methods, depending on what you do next.

My recommendation is never to send JSON as a request parameter. Set the request content type to application/json and send json as the request body. Then use @RequestBody to analyze it.

+14
source share

You can also use @RequestPart as follows:

 @RequestMapping(value = "/issues", method = RequestMethod.POST, headers = "Content-Type=multipart/form-data") public String uploadIssue(@RequestParam("image") MultipartFile file, @RequestPart("issue") MyMessage issue) 
+4
source share

All Articles