Spring RestTemplate unable to parse json response - java

If I parse the response of a POST as string it works perfectly:
ResponseEntity<String> stringResponse = restTemplate.postForEntity(DruidClient.QUERY_HOST + "/druid/v2", query, String.class);
String valueResults = stringResponse.getBody();
DruidValueResult[] results = new ObjectMapper().readValue(valueResults, DruidValueResult[].class);
However, if i tell spring to parse the response directly:
ResponseEntity<DruidValueResult[]> results = restTemplate.postForEntity(DruidClient.QUERY_HOST + "/druid/v2", query, DruidValueResult[].class);
I get the following error:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class [Lcom.dripstat.metricprocessor.druid.DruidValueResult;] and content type [application/smile]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:108)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:788)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:773)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:553)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:506)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:361)
Why isn't spring able to parse the resulting json directly?

From SpringSource Blog:
Objects passed to and returned from the methods getForObject(), postForLocation(), and put() and are converted to HTTP requests and from HTTP responses by HttpMessageConverters. Converters for the main mime types and Java types are registered by default, but you can also write your own converter and plug it in the RestTemplate. In the example below, I will show you how that's done.
I suppose the same for postForEntity(), so you may need to add a message converter for your specific mime type since it is not marshelled by default:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/smile" />
<property name="supportedMediaTypes" value="text/javascript" />
</bean>
</list>
</property>
</bean>

Related

How to handle 400 error in Spring MVC

I am getting 400 Http response when i am passing the invalid json format,
I would like to return the custom json message instead of this , can any one advise how to do in Spring 4.1 ?
Handling Execption using ControllerAdvice,but it is not working.
#ControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler({org.springframework.http.converter.HttpMessageNotReadableException.class})
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public String resolveException() {
return "error";
}
}
spring-config.xml is given below
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- Renders JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
Given below Json request and response from WebSphere application server (7.0).
Request 1: Empty json request : {}
Response Status Code: 400 Bad Request
Response Message : Json request contains invalid data:null
Request 2:Invalid format of Json Request : {"data":,"name":"java"}
Response Status Code: 400 Bad Request
Response or Exception message :
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected character (',' (code 44)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: com.ibm.ws.webcontainer.srt.http.HttpInputStream#8f308f3; line: 5, column: 57]
Similar question like below link
Using Spring MVC, accepting POST requests with bad JSON leads to a default 400 error code server page being returned
You can attempt to map the exception this way. This code will return a 400 status, but you can change the return the same way as is the link you posted
#ExceptionHandler
#ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleJsonMappingException(JsonMappingException ex) {}
Finally i have handle the exception via Servlet Filter with HttpServletRequestWrapper.
Step 1: Add the filter
Step 2: Get the request body from Customize HttpServletRequestWrapper class
Step 3: Convert request body json string to java object using JSON API
Step 4: Chain the request/response
Step 5: Catch exception / and update the HttpServlet Response
Using below reference.
Filter Example
HttpServletRequestWrapper Example
String to Json Object
With the help of this approach i can handle 400/405/415 Http Errors.
You may try this, in your pom.xml add dependency:
<!-- Need this for json to/from object -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
this will convert your java objects to JSON automatically when you return them. like you can write a class for response:
public class Response {
private int responseCode;
private String responseMessage;
//as many fields as you like
public Response (int responseCode, String responseMessage) {
this.responseCode = responseCode;
this.responseMessage = responseMessage;
} }
then you can return any java objects and they will be received as JSON,
#RequestMapping(value="/someMethod", method=RequestMethod.POST)
public #ResponseBody Response someMethod(#RequestBody Parameters param) {
return new Response(404, "your error message");
}

Converting array of Object to JSON and send it over HTTP

I have an array of object as ArrayList which I want to convert to JSON and send it to client over HttpResponse using Java and Jackson.
How I can do this?
Assuming you already put jackson library and using Spring framework. Mentioned following line in your spring context file.
<!-- Configure to plugin JSON as request and response in method handler -->
<beans:bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter" />
</beans:list>
</beans:property>
</beans:bean>
and Return the List/Map/Object from controller and it will internally convert it to JSON
For Non Spring:
doPost(HttpServletRequest req, HttpServletResponse resp)
{
ObjectMapper mapper = new ObjectMapper();
ArrayNode rootNode = mapper.readValue(req.getReader(), ArrayNode.class);
}
Source:
Passing array from javascript to java servlet using Jackson
http://software.danielwatrous.com/restful-java-servlet-serializing-tofrom-json-with-jackson/
Hope this helps :)
Do share your environment details if it was still not helpful and i will try to help :)

Turn off automatic view resolution spring 4

I am using the spring MVC template in IntelliJ to create a webservice to produce JSON from a rest call.
package com.planit.mvc;
#RestController
#RequestMapping("/rest")
public class BasicRestController {
#RequestMapping(value = "/test/{name}", produces = MediaType.APPLICATION_JSON_VALUE)
public Person test(#PathVariable String name) {
Person p = new Person();
p.setAge(10);
p.setFirstName(name);
p.setLastName(name);
return p;
}
}
The servlet dispatcher XML is as follows:
<context:component-scan base-package="com.planit.mvc"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
So when I navigate to the URL it throws an error as it's trying to resolve a view based on the {name} param of the URL.
What is the correct way to achieve what I am looking, while still allowing for automatic view resolution?
EDIT: When I call the url such as:
http://localhost:8080/rest/test/variable
So hitting the BasicRestController, with the method test due to the /test section of the url, followed by the PathVariable "variable" I get this error in tomcat:
HTTP Status 404 - /WEB-INF/views/rest/test/variable.jsp
So it looks like its trying to resolve the view variable.jsp which of course does not exist. I simply want it to give me back the JSON representation of the Person object, and not have to render it into a view.
I believe you're just missing <mvc:annotation-driven/> from your servlet context configuration. Don't forget to add the namespace declarations and schemaLocation values.

How to unmarshall a JSON object to a Java Class?

I have Spring REST application that can marshall an object to JSON when a GET request occurs. However what should I do for POST methods. I send a JSON object but it can't unmarshall it into a Java object. Here is a method of my controller:
#RequestMapping(value = "/user", method = RequestMethod.POST)
public void createUser(HttpServletResponse response, #RequestBody User user) {
...
response.setStatus(HttpServletResponse.SC_OK);
}
I send my JSON like that:
var userName = $('#userName').val();
var password = $('#password').val();
var mail = $('#mail').val();
var admin = $("#admin").is(':checked');
var user = {userName: userName, password: password, mail: mail, admin:admin};
$.ajax({
async : false,
type: 'POST',
contentType: 'application/json',
url: '/sfd/user',
data: user,
dataType: 'json',
success: function(data) {
...
},
error: function(data) {
...
}
});
PS:
Here: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/ it says:
If there are validation errors, a HTTP 400 is returned with the
error messages, otherwise a HTTP 200 is returned.
I have 400 Bad Request Error. Maybe the problem is related to that?
PS2: Should I send User object after I set all its elements? I mean User object has some other attributes, i.e. address but I don't set and send it from client.
PS3: When I debug AbstractHandlerExceptionResolver's resolveException method I see that error. It says 'u' is undefined character(I tested it that 'u' is the first key of JSON => userName's first character).
You should have the following setting in your XML:
<context:annotation-config/>
and then to make sure that jackson jar is in your classpath:
in my projects I prefer to set it as Spring Bean:
it will deserialize your json data to object.
You can read it more about it here:
http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
In the #RequestMapping set headers to accept application/json, and then try configuring this in your application context
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>

How to match wildcard accept header when using #RequestMapping in Spring framework

I have three resources:
#RequestMapping(value = "sample", method = RequestMethod.GET, headers = "Accept=text/html")
public ResponseEntity<String> sampleResourceHtml()
#RequestMapping(value = "sample", method = RequestMethod.GET, headers = "Accept=application/xml")
public ResponseEntity<String> sampleResourceXml()
#RequestMapping(value = "sample", method = RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<String> sampleResourceJson()
When a HTTP client accesses the url with Accept=*/* the webapp returns a 404
In this case I want to invoke sampleResourceHtml()
Changing "Accept=text/html" to "Accept=text/html, */*" will make my webapp accept requests with Accept=*/* which is what I want, however it will also accept requests with Accept=foo/bar which is not what I want.
How do I modify my code to return a supported media type for requests containing wildcards without returning an unexpected media type for unsupported requests?
You might find it easier to configure this in your context with the AnnotationMethodHandlerAdapter, so that the Accept header is automatically handled and the conversion done by Spring and not programmatically.
For example, you could use the following configuration:
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
<bean id="xmlMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="xstreamMarshaller"/>
</bean>
<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<ref bean="xmlMessageConverter"/>
<ref bean="jsonHttpMessageConverter"/>
</util:list>
</property>
</bean>
And modify the controller to return the object which Spring will convert to the required type.
#RequestMapping(value = "sample", method = RequestMethod.GET)
public ResponseEntity<String> sampleResource()
Note: You will need the relevant libraries on the classpath.

Categories

Resources