Using Spring 4.1.7 on JDK 1.8, I have an @RestController class that looks like this:
@RestController
public class ServiceAController {
public static final Logger LOG = Logger.getLogger(ServiceAController.class);
@RequestMapping(value="/rest/servicea", method=RequestMethod.POST)
public ServiceAResponse serviceA(@RequestParam(value="parmA", defaultValue="defaultParmA") String parmA,
@RequestParam(value="parmB", defaultValue="defaultParmB") String parmB,
@RequestParam(value="parmC", defaultValue="defaulParmC") String parmC) {
LOG.info("Inside Service A handler: " + parmA + " B: "+ parmB + " C: "+ parmC);
}
When I send a POST to /rest/servicea from a javascript like this, everything works, and I see the values "a", "b", and "c" printed in my log:
var data = {
"parmA": "a",
"parmB": "b",
"parmC": "c"
}
$.ajax({
type: "POST",
url: "./rest/servicea",
contentType: "application/x-www-form-urlencoded",
data: data,
dataType: "json",
success: submitAuthSuccess,
error: submitAuthFailure
})
However, when I try to change the call from the javascript to this (to change the protocol to REST rather than www-urlencode), I get the default values (defaultParmA, defaultParmB, defaultParmC) in my log:
var data = {
"parmA": "a",
"parmB": "b",
"parmC": "c"
}
$.ajax({
type: "POST",
url: "./rest/servicea",
contentType: "application/json",
data: JSON.stringify(data),
dataType: "json",
success: submitAuthSuccess,
error: submitAuthFailure
})
I think I'm missing something in the @RestController class to get it to parse the JSON rather than expecting www-urlencoded data.
I tried changing the @RequestMapping
annotation on the serviceA
method to add the consumes="application/json"
attribute, but that had no effect.
What can I change to make this work, using JSON rather than urlencoded data in the POST body?
The @RequestParam
javadoc states
Annotation which indicates that a method parameter should be bound to a web request parameter.
This is retrieved through the various ServletRequest
methods for request parameters. For example, ServletRequest#getParameterMap()
which states
Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.
In your second snippet, you aren't sending either. You're sending JSON in the request body.
Spring has a mechanism (it has many, and custom ones) for deserializing that into the data you expect. The standard solution is @RequestBody
, assuming you have an appropriately registered HttpMessageConverter
that can handle the JSON. Spring automatically registers MappingJackson2HttpMessageConverter
if you have Jackson 2 on the classpath, which can correctly deserialize JSON into Java POJO types.
The documentation gives a number of examples and explains how you would use it. With JSON, you could define a POJO type with fields that correspond to the ones you send
class RequestPojo {
private String paramA;
private String paramB;
private String paramC;
// and corresponding getters and setters
}
and add a @RequestBody
annotated parameter of this type to your handler method
public ServiceAResponse serviceA(@RequestBody RequestPojo pojo) {
pojo.getParamB(); // do something
return ...;
}
Jackson lets you define, through annotations or through configuration of the ObjectMapper
, how to deal with absent values.
@RestController
is not involved here. As its javadoc states,
Types that carry this annotation are treated as controllers where
@RequestMapping
methods assume@ResponseBody
semantics by default.