HTTP Status 406. Spring MVC 4.0, jQuery, JSON - java

I want to send JSON from my controller. I have the following configuration.
spring-servlet.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<mvc:resources mapping="/resources/**" location="/resources/"/>
<context:component-scan base-package="com.castle.controllers"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
.js :
function testAjax() {
var data = {userName: "MyUsername", password:"Password"};
$.ajax({
url: 'ajax/test.htm',
dataType : 'json',
type : 'POST',
contentType: "application/json",
data: JSON.stringify(data),
success: function(response){
alert('Load was performed.');
}
});
}
UserTest.java:
public class UserTest {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
TestAjaxController.java :
#Controller
#RequestMapping("/ajax")
public class TestAjaxController {
#RequestMapping(method = RequestMethod.POST, value = "/test.htm")
public #ResponseBody
UserTest testAjaxRequest(#RequestBody UserTest user) {
return user;
}
}
pom.xml :
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
When i do this request, i get in my Controller JSON represented as UserTest object. But on return :
HTTP Status 406 - The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
What i'm doing wrong? I know, there is a lot of questions about such cases, but i can't fix it for 2 days...
UPDATE
I Have found the solution!!
It's only need to return an Object. Not a User object or something.
But
return Object;
public #ResponseBody Object testAjaxRequest(#RequestBody UserTest user) {
List<UserTest> list = new ArrayList<>();
list.add(user);
list.add(user);
list.add(user);
return list;

The main issue here is that the path "/test.htm" is going to use content negotiation first before checking the value of an Accept header. With an extension like *.htm, Spring will use a org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy and resolve that the acceptable media type to return is text/html which does not match what MappingJacksonHttpMessageConverter produces, ie. application/json and therefore a 406 is returned.
The simple solution is to change the path to something like /test, in which content negotiation based on the path won't resolve any content type for the response. Instead, a different ContentNegotiationStrategy based on headers will resolve the value of the Accept header.
The complicated solution is to change the order of the ContentNegotiationStrategy objects registered with the RequestResponseBodyMethodProcessor which handles your #ResponseBody.

I had the same problem in the end it was the version of org.codehaus.jackson 1.9.x,
when I switched from 1.9.x jackson to 2.x (fasterxml) in my pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.2.3</version>
</dependency>
also is necesary : <mvc:annotation-driven />

I ran into this issue when upgrading Spring in a legacy project. The .html suffix of the AJAX endpoints (which were trying to return JSON) were indeed forcibly made to try to produce HTML due to the suffix, and since the handlers were returning an object, the request ended in a 406 error since Spring couldn't figure out how to make HTML out of a plain Java object.
Instead of altering the endpoint suffixes, or doing a complete configuration of a custom ContentNegotiationStrategy, making this change was enough:
<mvc:annotation-driven />
changed to:
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

Adding these lines to context configuration solved the same issue for me:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
I used Spring 4.1.x and Jackson 2.4.2

Make sure to use produces = "application/json" in your annotations.

Related

Some characters (e.g. brackets) are coming encoded in Spring #RequestBody. How to decode them?

Let's consider this fragment of code:
#ResponseBody
#RequestMapping(value = "/getFiltered", method = RequestMethod.POST)
public ResponseEntity<OraPhysicalGoodMiniDataWrapper> getFilteredProducts(#RequestBody OraSalesOfGoodsFilters filters) {
return oraProductListController.getFilteredProducts(filters);
}
filters parameter has String named searchValue.
The problem is: when I pass for example searchValue: "(2016)" in json, Spring controller receives searchValue=(2016).
I tried to decode it with Java URLDecoder but it didn't work.
And my question is:
is there any Java method which could decode all such characters in String? Or should I write my own method?
This is your problem solution. using javascript or spring settings.
Javascript
var param = {
"searchValue": "(2016)"
};
$.ajax({
type: 'POST',
dataType: 'JSON',
data: JSON.stringify(param),
contentType:"application/json; charset=UTF-8",
url: '/test/filter',
error: function() {
// error
},
success: function(returnJSON) {
// success
}
}):
Spring settings
Pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.0.4</version>
</dependency>
servlet.xml
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
As Joop Eggen mentioned in comment - the StringEscapeUtils.unescapeXml(String value)method proved to be helpful.
It's kind of werid that it's unescapeXml(), not unescapeJavaScript() (which is not working), because I pass the value on frontend as JSON (not XML) from JavaScript, but I'm glad it works.

Javers : #annotation(org.javers.spring.annotation.JaversAuditable) not working in some project

I have two projects, one is a real project and the second one is a demo project to try the Javers Framework with similar setting and similar environment. In the demo project, Javers audit trail is running well, but after I implementing it in the real project the Javers is not working.
I have investigated the process for several days and found this assumption
"Javers in the real project cannot detect the pointcut (more precisely cannot detect the annotation)" :
#AfterReturning("#annotation(org.javers.spring.annotation.JaversAuditable)") (in JaversAuditableAspect)
Because when I create a simple aspect with the same pointcut :
#AfterReturning("execution(* com.xxx.StatusRepository.*(..))")
the aspect is execute, and when I try to hit #annotation(org.javers.spring.annotation.JaversAuditable) with another pointcut (#Before, #After, #AfterThrowing, and #Around) no one pointcut is hit.
Is there any other clue or option so I can try it?
Here is my xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<tx:annotation-driven/>
<import resource="classpath:META-INF/spring/mbp-infra.xml" />
<import resource="classpath:META-INF/spring/mbp-util.xml" />
<import resource="classpath*:META-INF/spring/**/*-codelist.xml" />
<context:component-scan base-package="com.nttdata.mbp.domain" />
<!-- AOP. -->
<bean id="resultMessagesLoggingInterceptor"
class="org.terasoluna.gfw.common.exception.ResultMessagesLoggingInterceptor">
<property name="exceptionLogger" ref="exceptionLogger" />
</bean>
<aop:config proxy-target-class="true">
<aop:advisor advice-ref="resultMessagesLoggingInterceptor"
pointcut="#within(org.springframework.stereotype.Service)" />
</aop:config>
<aop:aspectj-autoproxy/>
<!-- check that the aop is running -->
<bean id = "myAspect" class = "com.nttdata.mbp.domain.util.AOPTest" />
</beans>
and here is my dependencies :
<!-- == Javers == -->
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-spring</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-persistence-jdbc</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-persistence-sql</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.polyjdbc</groupId>
<artifactId>polyjdbc</artifactId>
<version>0.6.4</version>
</dependency>
<!-- == End Javers == -->
=== Update ===
And here is my configuration for javers bean
#Configuration
public class AuditContext {
#Bean
public Javers javers() {
JaversRepository javersRepository = SqlRepositoryBuilder
.sqlRepository()
.withConnectionProvider(getConnectionProvider())
.withDialect(DialectName.MYSQL).build();
return JaversBuilder.javers()
.registerJaversRepository(javersRepository)
.build();
}
#Bean
public ConnectionProvider getConnectionProvider() {
return new AuditConnectionProvider();
}
#Bean
public AuthorProvider getAuthorProvider() {
return new SpringSecurityAuthorProvider();
}
#Bean
public CommitPropertiesProvider getCommitPropertiesProvider() {
return new CommitPropertiesProvider() {
#Override
public Map<String, String> provide() {
return ImmutableMap.of("key", "ok");
}
};
}
#Bean
public JaversAuditableAspect javersAuditableAspect() {
return new JaversAuditableAspect(javers(),getAuthorProvider(),getCommitPropertiesProvider());
}
#Bean
public JaversSpringDataAuditableRepositoryAspect javersSpringDataAuditableAspect() {
return new JaversSpringDataAuditableRepositoryAspect(javers(),getAuthorProvider(),getCommitPropertiesProvider());
}
}
As described in https://javers.org/documentation/spring-integration/
all you have to do is to enable the JaVers' aspect by declaring this bean:
#Bean
public JaversAuditableAspect javersAuditableAspect() {
return new JaversAuditableAspect(javers(), authorProvider(), commitPropertiesProvider());
}
and enable #AspectJ support.
Full example of Spring config is available here https://javers.org/documentation/spring-integration/#spring-jpa-example
(we don't have examples in xml, I suggest updating to Java Config)

trying to getAllCountries as xml returns 406 not acceptable

I have written a simple web service where I have been able to return json from the database values successfully and at this point I am trying to return the database values as xml from the database but getting 406 not acceptable. This is my honest attempt:
controller snippets
#RestController
public class CountryController {
#Autowired
CountryService countryService;
#RequestMapping(value = "/getAllCountries", method = RequestMethod.GET, headers = "Accept=application/xml")
public List<Country> getCountries() {
List<Country> listOfCountries = countryService.getAllCountries();
return listOfCountries;
}
this is my pojo class snippets
#XmlRootElement(name="Country")
#Entity
#Table(name="COUNTRY")
public class Country{
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.AUTO)
int id;
#Column(name="countryName")
String countryName;
#Column(name="population")
long population;
public Country() {
super();
}
a snippet of pom.xml showing dependent libraries I am using for the serialization to retrieve xml data
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
EDITTED TO SHOW XML CONFIG FILE
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<mvc:annotation-driven/>
<resources mapping="/resources/**" location="/resources/" />
On attempting the above using a rest client returns 406 not acceptable. Kindly assist.
Enable <mvc:annotation-driven/> in your spring
configuration. it supports convert object to/from XML file.
Use #ResponseBody after #RequestMapping. #ResponseBody annotations are used to bind the HTTP request/response body with a domain object in method parameter or return type.

Spring WS + JIBX "No adapter for endpoint" Error

I use JIBX to create my entity classes from XSD files. It is configured in pom.xml and creates classes when I do a "maven: compile"
I also use spring-ws. When I test my web service with SOAPUI I get the infamous error;
"No adapter for endpoint GetTransactionsResponse getTransactions(GetTransactionsRequest), Is your endpoint annotated with #Endpoint, or does.."
I checked all the threads here about that error but didn't help.
I have one Parent.xsd and it imports 2 child xsd's. They are all in the same folder. This is how my spring-ws-servlet looks like;
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean name="xsdCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="xsds">
<list>
<value>/WEB-INF/Parent.xsd</value>
</list>
</property>
</bean>
<context:component-scan base-package="mypackage"/>
<sws:annotation-driven/>
<sws:dynamic-wsdl id="my" portTypeName="myResource" locationUri="/ws/my"
targetNamespace="myschame">
<sws:xsd location="/WEB-INF/Parent.xsd"/>
</sws:dynamic-wsdl>
<sws:interceptors>
<bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor">
<property name="logRequest" value="true"/>
<property name="logResponse" value="true"/>
</bean>
<bean class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="xsdSchemaCollection" ref="xsdCollection"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
</sws:interceptors>
This is my endpoint class;
#Endpoint
public class TransactionsEndpoint {
public static final String NAMESPACE = "nmapespace";
#PayloadRoot(namespace = NAMESPACE, localPart = "getTransactionsRequest")
#ResponsePayload
public GetTransactionsResponse getTransactions(#RequestPayload GetTransactionsRequest request) {
GetTransactionsResponse transactionsResponse = new GetTransactionsResponse();
return transactionsResponse;
}
}
GetTransactionsResponse/Request classes created by JIBX.
My wsdl looks like this;
<wsdl:operation name="getTransactions"><wsdl:input message="tns:getTransactionsRequest" name="getTransactionsRequest">
</wsdl:input><wsdl:output message="tns:getTransactionsResponse" name="getTransactionsResponse">
</wsdl:output></wsdl:operation>
pom file is;
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ws.xmlschema</groupId>
<artifactId>xmlschema-core</artifactId>
<version>2.0.2</version>
</dependency>
I am not sure if the problem is because there are 3 xsd files and something goes wrong between those or it is a configuration problem with JIBX because When I try to use JAXB instead of JIBX, it worked!
Endpoint mappings are stored in a hashmap with a key based on the namespace and the local part of the #PayloadRoot annotation (see code below). You currently have (what I assume is) a typo in the namespace of the java class... nmapespace instead of namespace.
If this does not match up with what is located in your xsd and subsequently published wsdl (which are not shown), then the mapping would not be found. This is one (of the many) possible reasons that you would get that error.
public class PayloadRootAnnotationMethodEndpointMapping extends
AbstractAnnotationMethodEndpointMapping<QName> {
...
#Override
protected QName getLookupKeyForMethod(Method method) {
PayloadRoot annotation = AnnotationUtils.findAnnotation(method, PayloadRoot.class);
if (annotation != null) {
QName qname;
if (StringUtils.hasLength(annotation.localPart()) && StringUtils.hasLength(annotation.namespace())) {
qname = new QName(annotation.namespace(), annotation.localPart());
}
else {
qname = new QName(annotation.localPart());
}
return qname;
}
else {
return null;
}
}
If this is not the problem, you may need to add some more info to the question (soap request, xsds, wsdl).
I also had similar issue(spent several days) however in my case issue being Spring WS and Spring versions being incompatible, check whether your Spring WS and Spring versions match.

Spring REST XML service not accepting XML as "accept" header

I have several REST services defined that are currently returning JSON formatted objects as service response bodies. I'm trying to make this service also accept XML as a new requirement though it does not accept this.
I'm following the spring-mvc-showcase sample project and have setup my pom.xml dependencies almost identically, my service definitions likewise are very simple.
#Controller
#RequestMapping(value = "api/sales/*")
public class SalesController {
#RequestMapping(value = "/countries", method = RequestMethod.GET)
#ResponseBody
public List<NamedEntity> getCountries() {
NamedEntity has the appropriate #XmlRootElement annotation.
Could somebody explain the most basic requirements that I would need to get XML as a ResponseBody that the spring-mvc-showcase sample project is using.
EDIT: Added spring MVC sample.
The sample from the spring-mvc-showcase is as follows:
package org.springframework.samples.mvc.messageconverters;
#Controller
#RequestMapping("messageconverters/*")
public class MessageConvertersController {
#RequestMapping(value="/xml", method=RequestMethod.GET)
public #ResponseBody JavaBean writeXml() {
return new JavaBean("bar", "fruit");
Check the request header, client needs to have "application/xml" in the header, rather than "application/json "
Having said this make sure you have registered appropriate message converter for your object. If you are using Java 6 then Spring will auto detect JAXB in your classpath or else you can manually add the converter.
Add #Produces("application/xml") to getCountries()
You need to send "application/xml", not "application/application+xml". Also consider using:
#RequestMapping(value = "/countries", method = RequestMethod.GET, produces={"application/json", "application/xml"})
This ensures your method responds to those media types only and rejects others with 406 HTTP status code.
try this dispatcher servlet config.
<mvc:annotation-driven
content-negotiation-manager="contentManager" />
<bean id="contentManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="ignoreAcceptHeader" value="false" />
<property name="defaultContentType" value="application/json" />
<property name="useJaf" value="false" />
</bean>
and some dependency
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.4.3</version>
</dependency>

Categories