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");
}
Related
Sometimes JAR-RS clients are sending wrong syntactical request body. The server should response with HTTP status 400 (Bad Request), but it responses with HTTP status 500 (Internal Server Error).
Code:
JAX-B model class:
#XmlRootElement(namespace = "http://www.test.com/test")
#XmlAccessorType(value = XmlAccessType.FIELD)
public class TestModel {
#XmlElement
private String id;
}
JAX-RS resource class:
#Path("test")
public class TestResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void create(TestModel testModel) {
// some code
}
}
CXF configuration:
<jaxrs:server address="/rest" id="test" staticSubresourceResolution="true">
<jaxrs:serviceBeans>
<ref bean="testResource" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
Example:
Request body:
{"id2": "test"}
The id2 is wrong, so client should get a HTTP status 400, but it gets HTTP status 500.
Server log:
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "id2" (class test.TestModel), not marked as ignorable (one known property: "id"])
at [Source: org.apache.cxf.transport.http.AbstractHTTPDestination$1#6f30793d; line: 1, column: 10] (through reference chain: test.TestModel["id2"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:839)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1045)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1352)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1330)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:264)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1470)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:912)
at com.fasterxml.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:811)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1343)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1294)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:826)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:789)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:212)
... 68 more
Is there a way to configure Jackson and/or CXF to return HTTP status 400 for wrong syntactical request body without schema validation or bean validation?
The problem is that exceptions that aren't mapped to response (by way of ExceptionMappers), translate to a general server error response, as the runtime has no idea what to do with the exception.
The jackson-jaxrs-provider module has ExceptionMappers to handle the Jackson base exception class JsonMappingException and JsonParseException. The mappers are JsonMappingExceptionMapper and JsonParseExceptionMapper, respectively. These mappers will map the exception to a 400 response along with the exception message as the response body. If you do not like this response body, you can just write your own mapper.
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>
I migrated from Spring 3.1 to Spring 3.2.5. before migrating to Spring 3.2.5 everything seems to be working howerver when I updated my library some of my rest calls are returning a 400 Bad Request.
Here's the method
#RequestMapping(value = AJAX_SEARCH_MED)
#ResponseBody
DataTablesAjaxResponse<ActiveMedicationView> ajaxSearchActiveMedication(
#PathVariable(PATH_PIN) String pin,
#RequestBody DataTablesAjaxRequest request);
I already configured my mvc:annotation to this
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<!-- Turn off working out content type based on URL file extension, should fall back to looking at the Accept headers -->
<property name="favorPathExtension" value="false" />
</bean>
in my pom. I have this jackson marshalling library
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.10</version>
</dependency>
However when making calls from data tables I always receive a bad request.
The code calling the method
$('#prescriptionsTable').dataTable({
"bProcessing":true,
"bServerSide":true,
"bFilter":false,
"sAjaxSource":"/cms/ajax/patient/2012010000000009/active-medication.html",
"aoColumnDefs":[ //Other configurations here
Try this configuration:
#RequestMapping(value = AJAX_SEARCH_MED, method = RequestMethod.GET, headers="Content-Type=application/json")
#ResponseBody
public DataTablesAjaxResponse<ActiveMedicationView> ajaxSearchActiveMedication(
#PathVariable(PATH_PIN) String pin,
#RequestBody DataTablesAjaxRequest request)
{
// random code
};
If this doesn't fix it we can try to dig further to identify the problem.
I'm trying to return a JSON response with Spring 3.0.6, but I get a 406 response "Not Acceptable", with the description:
"The resource identified by this request is only capable of generating responses with characteristics
not acceptable according to the request "accept" headers ()."
I know that a very similar question has been asked before, but I can't make it work for my project, despite many
tests and I don't understand what I'm doing wrong.
In my Maven pom.xml I've the following:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.8.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.8.5</version>
<scope>compile</scope>
</dependency>
In web.xml I reference webmvc-config.xml, and the log confirms that is loaded.
<servlet>
<servlet-name>mainServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
In webmvc-config.xml I've the following:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
My Controller is:
#Controller
public class ClassifiedController {
#RequestMapping(value = "/classified/{idClassified}", headers = "Accept=*/*",
method = RequestMethod.GET)
#ResponseBody
public final Classified getClassified(#PathVariable final int idClassified) {
...
I tried with or without the headers parameter with the same results. If I call the URL
directly with Firefox the Request Headers contain the following (checked with firebug):
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
If I use the following JQuery:
$.ajax({
url: '/classified/38001',
type: 'GET',
dataType: 'json'
});
The following headers are sent:
Accept: application/json, text/javascript, */*; q=0.01
In both cases the result is a 406 error. I don't know what else should I check to make
it work.
UPDATE: I decided to debug through Spring and I found out that Jackson was called correctly and in org.codehaus.jackson.map.ser.StdSerializerProvider the method _findExplicitUntypedSerializer contains the following code:
try {
return _createAndCacheUntypedSerializer(runtimeType, property);
} catch (Exception e) {
return null;
}
This is unfortunate because hides the source of the problem. With the debugger I found out that that exception contained a very descriptive error message:
Conflicting getter definitions for property "reminded":
ClassifiedImpl#isReminded(0 params) vs
ClassifiedImpl#getReminded(0 params)
Now that I see the error message is a silly mistake and easy to fix, but without that it wasn't that obvious. In fact, fixing the problem, leaded to a working serialization.
Add the following in DispatcherServlet-servlet.xml.
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
I've stumbled upon the same error (406: content not acceptable) with Spring MVC and #RestController annotation.
The Spring handler:
#RequestMapping(value = "/stuff-acknowledgment/{id}", produces ="application/json;charset=UTF-8", headers="Accept=*")
public Message acknowledgeStuff(#PathVariable("id") String id, #ModelAttribute("ack") AckBean acquittement) {
Observation:
the URI has the form : http://www.host.com/stuff-acknowledgment/{id}
BUT $id has a very particular format: xxxcomplicatedhashxxx.png (or whatever extension you can think of).
Therefore:
Spring MVC interpret the extension and want to produce a result of that same mime type (even if I define it as a path variable), here an "image/png" MIME type even if I tell him to produce JSON. So a 406 exception is thrown.
Fix:
Remove the ".png" extension in the URI, or remove the PathVariable and put it in the body, or add a suffix behind the pathVariable (not tested but should work as well), the point is to avoid a file extension at the end of the URI.
P.S.: I know it doesn't answer the specific problem (with the solution in the update) in the question but I found that SO thread when searching for that problem and post my fix here for the record, hoping it can help someone in the future.
In terms of the MappingJacksonJson processing, you'll need to make sure that the Jackson ObjectMapper supports your object type for serialisation.
I ran into this problem because the objects that I wanted to return as JSON didn't have any getter methods for their properties. Jackson probably needs these. After adding them it worked.
although this thread is a little old...
u need to add the following (maven dependency):
org.codehaus.jacksonjackson-mapper-asl1.9.13
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>