I am working on a Spring MVC app. This application expects the client to send a XML in the request body. How can I extract this XML from the body and then create a DOM object?
I am using Spring 3.0
Thanks
Adi
Using the #RequestBody annotation:
The #RequestBody method parameter annotation indicates that a method
parameter should be bound to the value of the HTTP request body. For
example:
#RequestMapping(value = "/something", method = RequestMethod.PUT)
public void handle(#RequestBody String body, Writer writer) throws IOException
writer.write(body);
}
You convert the request body to the method argument by using an
HttpMessageConverter. HttpMessageConverter is responsible for
converting from the HTTP request message to an object and converting
from an object to the HTTP response body. The
RequestMappingHandlerAdapter supports the #RequestBody annotation with
the following default HttpMessageConverters:
ByteArrayHttpMessageConverter converts byte arrays.
StringHttpMessageConverter converts strings.
FormHttpMessageConverter converts form data to/from a MultiValueMap<String, String>.
SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.
Related
Im have #RestController and this method. how can I get any json and then select the handler depending on the method and pass it there for processing
PS. I use GSON instead of JACKSON
You can use #RequestBody in your method and take a String parameter:
public AbstractJsonResponse(#PaqthVariable String method, #RequestBody String json) {
...
}
See here: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestBody.html
Mainly the part that says:
Annotation indicating a method parameter should be bound to the body of the web request
I'm using RestTemplate to interact with several REST services, some of them accept/return JSON and some XML. To that end, I've added Jackson's dataformat-xml module as a dependency (along with the JAXB annotations module). RestTemplate automatically includes MappingJackson2XmlHttpMessageConverter (done in the RestTemplate constructor).
This creates a situation where some objects that are used as the request parameter in calls to
RestTemplate.postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)`
get serlialized as XML and the content-type of the request is set to application/xml. For example:
MyObject request = ...;
String url = ...;
MyResponseObject response = restTemplate.postForObject(url, request, MyResponseObject.class);
RestTemplate tries to serialize MyObject to XML and sets the request media type to application/xml.
Problem is, many of the services we call don't accept XML (they expect JSON). So now that I have MappingJackson2XmlHttpMessageConverter on the classpath, it's taking precedence over the JSON converter which makes the calls to JSON services fail.
I suppose I could change my calling code to pass an HttpEntity with the media type explicitly set to JSON instead of my simple data object, but that's kind of ugly (boilerplate) and would mean changing quite a few service calling code.
Is there a way to either
A) change the priority of the MessageConverters so that the standard Jackons (JSON) one takes priority over MappingJackson2XmlHttpMessageConverter
or
B) Prevent MappingJackson2XmlHttpMessageConverter from claiming that it can serialize the objects I don't want it to
?
I can see two options :
Create a RestTemplate with the HttpMessageConverter you want, in the order you want them to be used (check HttpEntityRequestCallback.doWithRequest they are used in the order they are in the list and the first matching converter will be used
As you suggested, using an HttpEntity and setting the Content-Type header to the mime type you want to get.
I think using a helper to create an HttpEntity with your object and the correct Content-Type header would be safer :
public class HttpEntityHelper {
public static <T> HttpEntity<T> jsonHttpEntity(T body) {
MultiValueMap<String, String> headers = new LinkedMultiValueMap();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return new HttpEntity(body, headers);
}
}
I'm trying to use the #InitBind annotation to map only certain fields on the object in the request body.
I have a spring controller defined in this way:
#RequestMapping(value = "addAddress", method = RequestMethod.POST)
public Object addAddressToPerson(
HttpServletRequest request,
HttpServletResponse res,
#RequestParam(value = "name", required = false) String name,
#RequestParam(value = "surname", required = false) String surname,
#RequestBody personDTO personJson,BindingResult result) {
The client request will be a a json representing a personDTO, but I don't want that field except the address to be mapped in the object for security reasons.
The input will be something like:
{ "address":"123 Street","........}
The personDTO contains many fields, and since spring map all of them directly in a DTO, that can be a problem.
I've seen that a solution is to use a Binder to declase the allowed or Disallowed field, but if I check the personDTO inside the controller, other fields are populate (for example if pass "id":"1234").
Any Hints?
The binder code is the following:
#InitBinder("orderJson")
protected void orderJsonBinder(WebDataBinder binder){
binder.setAllowedFields(new String[]{"address"});
}
Am I missing something?
Best Regards,
Luca.
But you are not binding request parameters to a model attribute bean, you are just asking spring to use an appropriate MessageConverter to convert the request body. As you say it is Json, you will use a MappingJackson2HttpMessageConverter (or MappingJacksonHttpMessageConverter with Jackson 1.x). The Spring Reference Manual says for this converter :
[This is an] HttpMessageConverter implementation that can read and write JSON using Jackson's ObjectMapper. JSON mapping can be customized as needed through the use of Jackson's provided annotations. When further control is needed, a custom ObjectMapper can be injected through the ObjectMapper property for cases where custom JSON serializers/deserializers need to be provided for specific types. By default this converter supports (application/json).
#InitBinder can only configure binding of #ModelAttribute annotated parameters. It is useless here. If Jackson annotations are not enough, you will have to use a custom object mapper.
And I am surprised that you can use a BindingResult after a #RequestBody parameter, because the documentation says that it should follow a #ModelAttribute one.
Iam getting null parameter values when i send values from rest client. But when I send Values from form(html view page) it is working fine.
Below one is my bean class.
public class Home {
private String id;
And I am sending values from rest client as post method.
{
"id":"10",
"load":"true"
}
Content-Type: application/json
Request is coming to the controller class. but it will return all values as null .But when I am sending values from html page it is working fine. Any one can help how to get values.
When I am using #RequestBody in controller calss, I am getting Caused by: org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported exception
The annotation #RequestBody should be added on Home homeRequest.
This allows the controller to analyze the request's body as the object's instance itself. This is the case of a JSON request.
Otherwise it is possible to use #RestController instead of #Controller as an annotation of the controller which does the same as #Controller, but it adds implicitly to all the request mapping methods the annotation #RequestBody to the inputs and #ResponseBody to all the response objects.
Is there an alternative way to obtain a reference to a request's body without using the approach with the annotation? I'm using GAE + Spring and everytime I use #RequestBody in the signatures of my controller methods, the server returns 415 Unsupported Media Type. All I'm trying to do is read a JSON encoded message on a Post method. Thanks.
You can take in a parameter of HttpServletRequest, and read the ServletInputStream using getInputStream() from there. The stream will contain the body of the request.
#Controller
public class MyController {
#RequestMapping("/test")
public String aTest(HttpServletRequest request) {
InputStream body = request.getInputStream();
//process request body
return myReturnVal;
}
}
Try this, on the RequestMapping configure the headers to accept application/json and be sure to configure a jackson message convertor for this type