Spring RESTful Web Service with JSON gives HTTP 406 error code - json

I am using Spring 3.2.5 to create a RESTful web service. To implement it I've used #ResponseBody tag. When I use InternalResourceViewResolver and try to load Html response then it is working fine. But when I call a URL which is marked as #ResponseBody then it gives HTTP 406 error code with error text as
The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
I have included Jackson jar files in my lib directory as well.
Here is my controller method which handles service request.
#ResponseBody
#RequestMapping (value = "/resp.htm")
public Data jsonResp() {
Data d = new Data();
d.setName("TEst");
d.setAddr("Address....");
return d;
}
There are lots of questions have been asked & answered, I've tried many of them, but it still gives the same result. Then I came across a new kind of answer, which was stating to use ContentNegotiatingViewResolver. By using it I am able to view response in intended format. That is JSON format.
After using ContentNegotiatingViewResolver, servlet dispatcher code looks like this:
<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>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2" />
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
So, my question is, whenever we require to use Spring's Web Service feature, do we must require to have ContentNegotiatingViewResolver?

Add gson in your class path. as well as jackson

I had a similar issue while calling a spring rest service from angular 8 for uploading a file. I was using ResponseEntity to encapsulate the success or failure message for which I was having the 406 response. all I did was in the UI side this.httpClient.post(url, formData,{responseType: 'text'}) and I was able accept the string as response from the service response.

The annotation #ResponseBody used with custom class types, generally uses MappingJackson2HttpMessageConverter to convert the object to JSON and return it in application/json content.
Since your request doesn't contain an Accept header for application/json, Spring deems the content it's creating as unacceptable and instead returns a 406.
You could simply change your request to add the Accept header. (You can't do this easily in a browser).

In my case the request had .html suffix and received this error. Once removed, it worked fine.

All you need to do is to add jackson libraries to your classpath find them Here

Related

I want my controlleradvice to always produce JSON when handling exceptions

I have centralized my exception handling for my rest service into a neat ControllerAdvice.
I am returning regular transfer-objects, in the hope of my cool mapping-jackson-converter will convert it into JSON for the end client.
Now here's the thing. If i don't set the accept-header to "Application/JSON", i don't get the converted JSON, i get some default HTML instead, in my tests seemingly generated by Jetty. I have to admit i'm not sure why, but i guess it's some default Spring resolver that comes into effect.
This got me thinking. Clients who call my rest URL's should know that i return JSON, so i would like my service to always return json regardless.
Is there some way to configure the ReqeustMappingHandlerAdapter to always produce JSON?
my current config:
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonConverter"/>
</beans:list>
</beans:property>
</beans:bean>
<!-- Instantiation of the converter in order to configure it -->
<beans:bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<!--beans:property name="supportedMediaTypes" value="application/json"/-->
</beans:bean>
I don't know if this answers your question, but you could set the default content type in your Spring configuration to JSON (it defaults to HTML without the Accept header in Spring MVC). Here is a sample configuration:
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/json" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
Source:
http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc

CXF JSON Schema Validation

I am writing RESTFul webservices which support both XML and JSON format. I need to add schema validation in the webservices. My beans are auto generated using JAX-B. As suggested at CXF's site at Schema validation, I am using org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider as JSON provider and org.apache.cxf.jaxrs.provider.JAXBElementProvider as JAX-B provider. The request and response is working fine but now I want to add schema validation.
The sample code at above CXF link is not working for me for JSON schema validation (its working for XML schema validation). They shown it for org.apache.cxf.jaxrs.provider.json.JSONProvider (under 'Schema Validation' section) which doesn't work for me as my beans are JAX-B generated, so I am using JacksonJaxbJsonProvider.
Is there any solution for this problem? Could somebody please suggest some approach that I can try?
Below is the XML configuration:
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/>
<bean id="schemaHolder" class="org.apache.cxf.jaxrs.utils.schemas.SchemaHandler">
<property name="schemas" ref="theSchemas"/>
</bean>
<util:list id="theSchemas">
<value>classpath:/WEB-INF/classes/po.xsd</value>
</util:list>
<!-- Person REST Service Configurations -->
<bean id="personRESTServiceImpl" class="com.abc.webservices.service.rest.PersonRESTService" />
<jaxrs:server id="personRESTService" address="/person-rest-service">
<jaxrs:serviceBeans>
<ref bean="personRESTServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="jaxbProvider" />
<ref bean='jsonProvider' />
</jaxrs:providers>
</jaxrs:server>
Your classpath is wrong, in web application classpath is WEB-INF/classes
Hence you can use following configuration
<jaxrs:schemaLocations>
<jaxrs:schemaLocation>classpath:po.xsd</jaxrs:schemaLocation>
</jaxrs:schemaLocations>
if you have xsd directory in classes directory then classpath:xsd/po.xsd

NoSuchMessageException when using a custom message converter along formatters

I'm using Spring 3.2 M1 and Hibernate 3.
I was working with formatters to format POJOs (which happen to be Hibernate mapping entities) to their string representation. This was very convenient as it worked the other way around allowing me to bind string values to objects. The config in xml was:
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="aa.XFormatter" />
<bean class="aa.YFormatter" />
<bean class="bb.ZFormatter" />
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="aa.DateFormatterRegistrar" />
</set>
</property>
</bean>
Everything was working fine until I needed to add a custom object mapper (HibernateAwareObjectMapper using jackson-module-hibernate) to get rid of lazy loading issues with hibernate POJOs when jsonifiying responses from the back end. I added this to the above code:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="cc.HibernateAwareObjectMapper"></bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
This had the effect of fixing the lazy loading issue. But a new error surfaced when invoking the formatters (when binding a string to a Date for ex):
org.springframework.context.NoSuchMessageException: No message found under code 'fieldOfX.depended' for locale 'en_US'.
at org.springframework.context.support.AbstractMessageSource.getMessage(AbstractMessageSource.java:161)...
fieldOfX being a field of type Date that was perfectly formatted from its string representation to its Date/object representation before adding the custom object mapper. And I am curious to know what does depended stand for.
The other weird thing for me is that formatting from object to string seems to work just fine.
To my understanding, formatters are just special converters. And message converters are just another kind of converters. But I'm beginning to sense that I'm wrong on this one.
So what am I doing/understanding wrong? Any help is welcome.
Sorry for wasting everybody's time here but the issue was solved by upgrading to the stable version 3.2.2.RELEASE.
Thank you #Pavel Horal for pointing that out.

Spring Restful, Post multiple formats like json/xml/domain object into same action

I am writing a Spring Restful webservices application using Spring MVC. I have used content negotiating viewer to respond multiple data formats for eg. If some one requests a URL with .xml extension an XML will be sent in response body similarly if someone requests with an .json extension, an json will be sent in response body.
Now, I want the same process inwards, say if some body wants to post a Json or xml or a simple post from a webpage form using post method to same action, it should be able to handle all these.
This way i will be able to write a Web Service+Web Application in a single Spring MVC+Restful Application.
Thanks in advance for the help :)
You can use headers attribute of #RequestMapping annotation.
#RequestMapping(value = "/pets", method = RequestMethod.POST, headers="content-type=text/*")
to narrow content-type of requests your method is going to serve.
edit:
If you want to sent different content type in request body, then the only thing you need to do is to define MessageConverter (I assume you already did that) and annotate your method parameter with
#RequestBody
Spring should deserialize the body of your request using the MessageConverter you defined.
So assuming you have something like:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</util:list>
</property>
</bean>
<bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<util:map>
<entry key="json" value="application/json"/>
</util:map>
</property>
<property name="defaultViews">
<util:list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</util:list>
</property>
</bean>
in your spring context.
Annotating your method like this:
#RequestMapping(method=PUT, value="/user/{user_id}")
public void putUser(#RequestBody User user, #PathVariable int user_id) {
...
}
should do the job.
You don't have to do anything. You register converts and they will in turn tell "spring" what Content-types they can handle. XStream registers application/xml and text/xml (perhaps more), jackson registers application/json and so on.
It's all available at http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
I also don't like the filename-standard, I prefer to leave that to the same converter. In that case it will look at the Accept-header. If you want json, set Accepts: application/json.

spring prefixjson with responsebody

when controller method return is #responsebody , even if i put
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="true" />
</bean>
there will no && {} insert at the front of json data. anyone knows what is reason?
JSON in #RequestBody/#ResponseBody is handled by MappingJacksonHttpMessageConverter which is configured in AnnotationMethodHandlerAdapter.messageConverters.
The easy way to configure it without interference with other features is to create a BeanPostProcessor to intercept creation of AnnotationMethodHandlerAdapter, see, for example, here.