I have written a spring MVC application using the spring tools for eclipse and deployed it onto an tomcat 7 environment on AWS Elastic Beanstalk. But when I try to return JSON I get the following error.
406- The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
But when I run the same application locally on glassfish server it runs perfectly and returns the intended json as follows:
{"id":1,"message":"Hello, World!","description":"Hello, World!"}
Here is my code:
Controller code :
private static final String template = "Hello, %s!";
private final AtomicInteger counter = new AtomicInteger();
#RequestMapping(value = "/greeting",headers="Accept=*/*",method = RequestMethod.GET)
public #ResponseBody ResponseBean greeting(#RequestParam(value="name", required=false, defaultValue="World") String name,HttpServletResponse response , ModelMap model){
response.setContentType("application/json");
return new ResponseBean(counter.incrementAndGet(),String.format(template, name),String.format(template, name));
}
My Response Bean Code :
package com.ramesh.beans;
public class ResponseBean {
private final int id;
private final String message;
private final String description;
public ResponseBean(int id,String message,String desc){
this.id = id;
this.message = message;
this.description = desc;
}
public int getId() {
return id;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
}
My servlet-context.xml file :
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.ramesh.ws" />
</beans:beans>
Could anyone please help me out ?. I am willing to provide any more information about my program if needed.
My request headers on chrome are as follows :
They are as follows :
1 requests ❘ 1.3 KB transferred ❘ 250 ms (load: 256 ms, DOMContentLoaded: 257 ms)
HeadersPreviewResponseTiming
Remote Address:54.206.99.113:80
Request URL:http://ramesh-dev-gvssfipguk.elasticbeanstalk.com/greeting
Request Method:GET
Status Code:406 Not Acceptable
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6,ms;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Host:ramesh-dev-gvssfipguk.elasticbeanstalk.com
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36
Response Headers
Connection:keep-alive
Content-Length:1070
Content-Type:text/html;charset=utf-8
Date:Tue, 20 May 2014 10:14:45 GMT
Server:Apache-Coyote/1.1
X-Cache:MISS from tx33vspep22a
I finally fixed it by updating my controller method as shown below:
#RequestMapping(value = "/greeting",produces="application/json",method = RequestMethod.GET)
public #ResponseBody ResponseBean greeting(#RequestParam(value="name", required=false, defaultValue="World") String name,HttpServletResponse response , ModelMap model){
response.setContentType("application/json");
return new ResponseBean(counter.incrementAndGet(),String.format(template, name),String.format(template, name));
}
It seems when deploying to tomcat I need the produces="application/json" property.
Related
Now I am making project with REST API for the smart flat. I am using Spring, Spring, Hibernate, MySql.
For now I have created entity for user and I faced with such exception when I try retrieve the user by my API:
Could not write JSON: could not initialize proxy - no Session;
I have found the solution how to prevent this exception by next links
JsonMappingException: could not initialize proxy - no Session
What does #Proxy(lazy = false) do?
#Proxy(lazy = false) - has solved my problem, but I realy don't understand why session is closed in the spring controller when i try to get the user?
When I persist the user - no such exception! Nevertheless that the same service is used for persisting and getting objects. How can it be?
Logic of my application is started from web.xml. I am using
org.springframework.web.servlet.DispatcherServlet
This servlet maps requests and transfer to my controller. I am using spring json message converter
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
Configuration for spring's dispatcherServlet is
<mvc:annotation-driven/>
<context:component-scan base-package="com.smartcore.controllers.mysql"/>
<!-- Configure to plugin JSON as request and response in method handler -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
My Entity is simple and doesn't have any relations with othe entities
#Entity
#Table(name = "User")
//#Proxy(lazy = false)
public class UserMySql {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Column(name = "email")
private String eMail;
#Column(name = "login")
private String login;
#Column(name = "password")
private String password;
public UserMySql() {}
public UserMySql(String name, String surname, String login, String password, String eMail) {
this.name = name;
this.surname = surname;
this.login = login;
this.password = password;
this.eMail = eMail;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String geteMail() {
return eMail;
}
public void seteMail(String eMail) {
this.eMail = eMail;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UserMySql [id=");
sb.append(id);
sb.append(", name=");
sb.append(name);
sb.append(", surname=");
sb.append(surname);
sb.append(", eMail=");
sb.append(eMail);
sb.append(", login=");
sb.append(login);
sb.append(", password=");
sb.append(password);
sb.append("]");
return sb.toString();
}
Code for Controller
#RestController
public class MySqlUserAccountController {
private UserMySqlService userMySqlService;
#Autowired
public MySqlUserAccountController( UserMySqlService userMySqlService) {
this.userMySqlService = userMySqlService;
};
#GetMapping("/user/{userId}")
public #ResponseBody UserMySql findUserById(#PathVariable("userId") Long userId) {
return userMySqlService.getUserById(userId);
}
#PostMapping("/user/add")
public void addUser(#RequestBody UserMySql user){
userMySqlService.save(user);
}
}
I am using Spring data and it was used native methot of JpaRepository getOne(id) to retrieve user.
return this.userRepo.getOne(id);
Also I have found the solution to use
org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
But configuring filter and adding bean session has not helped.
web.xml added
<servlet-mapping>
<servlet-name>dispServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
<!-- Replace with hibernate3, hibernate4 or hibernate5 depending on the
hibernate version one uses -->
</filter>
application-context.xml added
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.smartcore.entities.mysqldb"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
What is best way for implementation? and if use #Proxy(lazy = false)- that lead to live link to my object from any object contains it, can it lead to the increasing memory consumption?
In previous answers I have not found reason why session was invalidated in the controller. Could you please describe in more details what is trhe reason?
Update
I still has not solved problem with lazy loading. I found solution described here
http://blog.pastelstudios.com/2012/03/12/spring-3-1-hibernate-4-jackson-module-hibernate/
But in my case it doesnt't work and I don't understand why ?
web.xml config
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- Processes application requests -->
<servlet>
<servlet-name>dispServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
dispatcher-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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.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-4.3.xsd">
<context:component-scan base-package="com.smartcore.controllers.mysql" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.smartcore.mappers.json.HibernateAwareObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
</beans>
HibernateAwareObject
public class HibernateAwareObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 5371945173448137189L;
public HibernateAwareObjectMapper() {
this.registerModule(new Hibernate5Module());
}
}
In the log I don't see that my custom object will be called. It looks like something with configuration.
2017-11-17 13:58:50 DEBUG DispatcherServlet:891 - DispatcherServlet
with name 'dispServlet' processing GET request for
[/Smart_Core_Control/user/3] 2017-11-17 13:58:50 DEBUG
RequestMappingHandlerMapping:313 - Looking up handler method for path
/user/3 2017-11-17 13:58:50 DEBUG RequestMappingHandlerMapping:320 -
Returning handler method [public
com.smartcore.entities.mysqldb.UserMySql
com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long)]
2017-11-17 13:58:50 DEBUG DefaultListableBeanFactory:255 - Returning
cached instance of singleton bean 'mySqlUserAccountController'
2017-11-17 13:58:50 DEBUG DispatcherServlet:979 - Last-Modified value
for [/Smart_Core_Control/user/3] is: -1 2017-11-17 13:58:50 DEBUG
TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource:354
- Adding transactional method 'getOne' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; '' 2017-11-17
13:58:50 DEBUG DefaultListableBeanFactory:255 - Returning cached
instance of singleton bean 'transactionManager' 2017-11-17 13:58:50
DEBUG JpaTransactionManager:368 - Creating new transaction with name
[org.springframework.data.jpa.repository.support.SimpleJpaRepository.getOne]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; '' 2017-11-17
13:58:50 DEBUG JpaTransactionManager:391 - Opened new EntityManager
[SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0}
updates=ExecutableList{size=0} deletions=ExecutableList{size=0}
orphanRemovals=ExecutableList{size=0}
collectionCreations=ExecutableList{size=0}
collectionRemovals=ExecutableList{size=0}
collectionUpdates=ExecutableList{size=0}
collectionQueuedOps=ExecutableList{size=0}
unresolvedInsertDependencies=null])] for JPA transaction 2017-11-17
13:58:50 DEBUG DriverManagerDataSource:143 - Creating new JDBC
DriverManager Connection to [jdbc:mysql://localhost:3306/core_data]
Fri Nov 17 13:58:50 EET 2017 WARN: Establishing SSL connection without
server's identity verification is not recommended. According to MySQL
5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance
with existing applications not using SSL the verifyServerCertificate
property is set to 'false'. You need either to explicitly disable SSL
by setting useSSL=false, or set useSSL=true and provide truststore for
server certificate verification. 2017-11-17 13:58:50 DEBUG
DataSourceUtils:176 - Setting JDBC Connection
[com.mysql.cj.jdbc.ConnectionImpl#29154676] read-only 2017-11-17
13:58:50 DEBUG TransactionImpl:55 - begin 2017-11-17 13:58:50 DEBUG
JpaTransactionManager:423 - Exposing JPA transaction as JDBC
transaction
[org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#34dcedf7]
2017-11-17 13:58:50 DEBUG JpaTransactionManager:739 - Initiating
transaction commit 2017-11-17 13:58:50 DEBUG JpaTransactionManager:531
- Committing JPA transaction on EntityManager [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0}
updates=ExecutableList{size=0} deletions=ExecutableList{size=0}
orphanRemovals=ExecutableList{size=0}
collectionCreations=ExecutableList{size=0}
collectionRemovals=ExecutableList{size=0}
collectionUpdates=ExecutableList{size=0}
collectionQueuedOps=ExecutableList{size=0}
unresolvedInsertDependencies=null])] 2017-11-17 13:58:50 DEBUG
TransactionImpl:66 - committing 2017-11-17 13:58:50 DEBUG
DataSourceUtils:233 - Resetting read-only flag of JDBC Connection
[com.mysql.cj.jdbc.ConnectionImpl#29154676] 2017-11-17 13:58:50 DEBUG
JpaTransactionManager:622 - Closing JPA EntityManager
[SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0}
updates=ExecutableList{size=0} deletions=ExecutableList{size=0}
orphanRemovals=ExecutableList{size=0}
collectionCreations=ExecutableList{size=0}
collectionRemovals=ExecutableList{size=0}
collectionUpdates=ExecutableList{size=0}
collectionQueuedOps=ExecutableList{size=0}
unresolvedInsertDependencies=null])] after transaction 2017-11-17
13:58:50 DEBUG EntityManagerFactoryUtils:419 - Closing JPA
EntityManager 2017-11-17 13:58:50 DEBUG
ExceptionHandlerExceptionResolver:137 - Resolving exception from
handler [public com.smartcore.entities.mysqldb.UserMySql
com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long)]:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: could not initialize proxy - no Session; nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
could not initialize proxy - no Session 2017-11-17 13:58:50 DEBUG
ResponseStatusExceptionResolver:137 - Resolving exception from handler
[public com.smartcore.entities.mysqldb.UserMySql
com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long)]:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: could not initialize proxy - no Session; nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
could not initialize proxy - no Session 2017-11-17 13:58:50 DEBUG
DefaultHandlerExceptionResolver:137 - Resolving exception from handler
[public com.smartcore.entities.mysqldb.UserMySql
com.smartcore.controllers.mysql.MySqlUserAccountController.findUserById(java.lang.Long)]:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: could not initialize proxy - no Session; nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
could not initialize proxy - no Session 2017-11-17 13:58:50 WARN
DefaultHandlerExceptionResolver:380 - Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write JSON: could not initialize proxy - no Session; nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
could not initialize proxy - no Session 2017-11-17 13:58:50 DEBUG
DispatcherServlet:1076 - Null ModelAndView returned to
DispatcherServlet with name 'dispServlet': assuming HandlerAdapter
completed request handling 2017-11-17 13:58:50 DEBUG
DispatcherServlet:1004 - Successfully completed request
What can be wrong?
You are returning an object via #Responsebody, userObject which you are returning is proxy object as you using is `LAZY' fetch. In controller layer there is no longer active transaction to fetch the properties of entity object.
You can either do EAGER fetching for of object or make declare child properties as Transient.
I am building a simple Spring MVC webapp and was developing on jetty. My controller binding used this:
#RequestMapping(value = RESTRoutes.CREATE_DOC, method = RequestMethod.POST)
public #ResponseBody String getDoc
And returning a String from a JSONObject correctly resolves to JSON in my ajax response.
But using those same controllers, i deployed my gradle war to tomcat and my json came back wrapped as true strings.
So i changed my headers to use Map and that seems to fix things in both jetty and tomcat:
#RequestMapping(value = RESTRoutes.CREATE_DOC, method = RequestMethod.POST)
public #ResponseBody Map<String, String> getDoc
I convert from the string to a map with this:
HashMap<String, String> jsonResponse = new HashMap<String, String>();
if(claimFolder.has("error")){
response.setStatus(500);
}else{
jsonResponse = new ObjectMapper().readValue(claimFolder.toString(), HashMap.class);
}
return jsonResponse;
My question is why this is nessesary?
Here's my jackson converter configuration:
<bean id="formConverter" class="org.springframework.http.converter.FormHttpMessageConverter" />
<!-- add byte[] converter -->
<bean id="byteArrayConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
<property name="supportedMediaTypes" value="application/octet-stream" />
</bean>
<!-- add in our JSON message converter -->
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json;charset=UTF-8" />
</bean>
<!-- add in our plain string message converter -->
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8" />
</bean>
<!-- Expose the authenticated handler to all beans that have been declared via annotation -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>
TL;DR: Why does jetty and tomcat return stringified JSON differently?
Well, it's absolutely normal for Spring content negotiation to translate a String object as a simple string without marshalling it to a JSON object. In order to serialize a java String object in JSON object you need to wrap it previously in some java class. For example:
QuestionStatus {
private String status;
public QuestionStatus(String status) {
this.status = status;
}
public getStatus() {
return status;
}
}
Hence you have to return in your Controller method not a String but QuestionStatus.
I have some huge trouble receiving JSON from my simple Spring Controller although I checked against many other tutorials and even the official spring blog and could not find any difference, so please help me.
So my dependencies in my project are:
spring-context 3.2.2 RELEASE
spring-web 3.2.2 RELEASE
spring-webmvc 3.2.2 RELEASE
spring-test 3.2.2 RELEASE
junit 4.10
servlet-api 2.5
atmosphere-runtime 1.1.0 RC4
logback-classic 1.0.13
libthrift 0.9.0
jackson-mapper-asl 1.9.12
jackson-core-asl 1.9.12
My Controller is very simple and just generates a random UUID and returns it. It looks as follows:
#Controller
public class SimpleController {
#RequestMapping(value="/new", method=RequestMethod.GET)
public #ResponseBody SimpleResponse new() throws JsonGenerationException, JsonMappingException, IOException {
SimpleResponse sr = new SimpleResponse();
sr.setId(UUID.randomUUID().toString());
return sr;
}
}
The model is just a simple POJO like
public class SimpleResponse {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Configuration is done like this
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
<display-name>SimpleTest</display-name>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
and
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="de.tum.ibis.wsc" />
</beans>
So thats the server side. On the client side I have a html page with just one line of jQuery code
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src="http://code.jquery.com/jquery.js"></script>
<script>
$(document).ready(function() {
$.getJSON("http://localhost:8080/Frontend/app/new", function(data) { console.log("it works"); });
});
</script>
</head>
<body>
</body>
</html>
Now according to everything I have read this should work but it does not for me. If I call localhost:8080/Frontend/app/new directly in my browser I get something like this: {"id":"b46b8d67-5614-44ed-90ef-d2da14d260f6"} and Firebug tells me that the response header from the server is
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Server: Jetty(7.6.5.v20120716)
so content-type should be fine. Well if I now run the jquery ajax call I get the error "JSON.parse: unexpected end of data " in jquery.js and I have no cloue why. I hope anybody can help me with that. Thanks!
------ Update ------
Firebug: jQuery error
Firebug: All I get
Firebug: This is what I get if a access the url directly
Try configuring ContentNegotiationManagerFactoryBean in Spring XML config, see Spring docs
Set favorPathExtension to false and update method's #RequestMapping like so
#RequestMapping(value="/new", method=RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
In your AJAX request, you're using
http://localhost:8080/Frontend/app/new
And your servlet declares URL "/new", you should use "/app/new" instead.
#RequestMapping(value="/app/new", method=RequestMethod.GET)
According to http://wiki.fasterxml.com/JacksonFAQDateHandling, “DateTime can be automatically serialized/deserialized similar to how java.util.Date is handled.” However, I am not able to accomplish this automatic functionality. There are StackOverflow discussions related to this topic yet most involve a code-based solution, but based upon the quote above I should be able to accomplish this via simple configuration.
Per http://wiki.fasterxml.com/JacksonFAQDateHandling I have my configuration set so that writing dates as timestamps is false. The result is that java.util.Date types are serialized to ISO 8601 format, but org.joda.time.DateTime types are serialized to a long object representation.
My environment is this:
Jackson 2.1
Joda time 2.1
Spring 3.2
Java 1.6
My Spring configuration for the jsonMapper bean is
#Bean
public ObjectMapper jsonMapper() {
ObjectMapper objectMapper = new ObjectMapper();
//Fully qualified path shows I am using latest enum
ObjectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.
WRITE_DATES_AS_TIMESTAMPS , false);
return objectMapper;
}
My test code snippet is this
Date d = new Date();
DateTime dt = new DateTime(d); //Joda time
Map<String, Object> link = new LinkedHashMap<String, Object>();
link.put("date", d);
link.put("createdDateTime", dt);
The resulting snippet of JSON output is this:
{"date":"2012-12-24T21:20:47.668+0000"}
{"createdDateTime": {"year":2012,"dayOfMonth":24,"dayOfWeek":1,"era":1,"dayOfYear":359,"centuryOfEra":20,"yearOfEra":2012,"yearOfCentury":12,"weekyear":2012,"monthOfYear":12 *... remainder snipped for brevity*}}
My expectation is that the DateTime object should matche that of the Date object based upon the configuration. What am I doing wrong, or what am I misunderstanding? Am I reading too much into the word automatically from the Jackson documentation and the fact that a string representation was produced, albeit not ISO 8601, is producing the advertised automatic functionality?
I was able to get the answer to this from the Jackson user mailing list, and wanted to share with you since it is a newbie issue. From reading the Jackson Date FAQ, I did not realize that extra dependencies and registration are required, but that is the case. It is documented at the git hub project page here https://github.com/FasterXML/jackson-datatype-joda
Essentially, I had to add another dependency to a Jackson jar specific to the Joda data type, and then I had to register the use of that module on the object mapper. The code snippets are below.
For my Jackson Joda data type Maven dependency setup I used this:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.version}</version>
</dependency>
To register the Joda serialization/deserialization feature I used this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JodaModule());
objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.
WRITE_DATES_AS_TIMESTAMPS , false);
Using Spring Boot.
Add to your Maven configuration...
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.7.5</version>
</dependency>
Then to your WebConfiguration...
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter
{
public void configureMessageConverters(List<HttpMessageConverter<?>> converters)
{
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
final ObjectMapper objectMapper = new ObjectMapper();
//configure Joda serialization
objectMapper.registerModule(new JodaModule());
objectMapper.configure(
com.fasterxml.jackson.databind.SerializationFeature.
WRITE_DATES_AS_TIMESTAMPS , false);
// Other options such as how to deal with nulls or identing...
objectMapper.setSerializationInclusion (
JsonInclude.Include.NON_NULL);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
converter.setObjectMapper(objectMapper);
converters.add(converter);
super.configureMessageConverters(converters);
}
}
In Spring Boot the configuration is even simpler. You just declare Maven dependency
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
</dependency>
and then add configuration parameter to your application.yml/properties file:
spring.jackson.serialization.write-dates-as-timestamps: false
I thought I'd post an updated working example using:
Spring 4.2.0.RELEASE, Jackson 2.6.1, Joda 2.8.2
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven>
<message-converters>
<beans:bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="objectMapper" ref="objectMapper" />
</beans:bean>
</message-converters>
</annotation-driven>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="objectMapper"
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<beans:property name="featuresToDisable">
<beans:array>
<util:constant
static-field="com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS" />
</beans:array>
</beans:property>
<beans:property name="modulesToInstall"
value="com.fasterxml.jackson.datatype.joda.JodaModule" />
</beans:bean>
<beans:bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<beans:property name="defaultLocale" value="en" />
</beans:bean>
<!-- Configure the Message Locale Resources -->
<beans:bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="errors" />
</beans:bean>
<beans:bean id="versionSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="version" />
</beans:bean>
<!-- DataSource -->
<beans:bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<beans:property name="jndiName" value="java:comp/env/jdbc/TestDB" />
</beans:bean>
<!-- POJO: Configure the DAO Implementation -->
<beans:bean id="publicationsDAO"
class="com.test.api.publication.PublicationsDAOJdbcImpl">
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
<!-- Things to auto-load -->
<context:component-scan base-package="com.test.api" />
<context:component-scan base-package="com.test.rest" />
</beans:beans>
API Code
package com.test.api.publication;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
#JsonRootName("event")
#JsonIgnoreProperties(ignoreUnknown=true)
public class Publication {
private Map<String, Object> tokens;
private String href;
private String policy_path;
#JsonProperty("tokens")
public Map<String, Object> getTokens() {
return tokens;
}
#JsonProperty("tokens")
public void setTokens(Map<String, Object> tokens) {
this.tokens = tokens;
}
#JsonProperty("href")
public String getHref() {
return href;
}
#JsonProperty("href")
public void setHref(String href) {
this.href = href;
}
#JsonProperty("policyPath")
public String getPolicyPath() {
return policy_path;
}
#JsonProperty("policyPath")
public void setPolicyPath(String policy_path) {
this.policy_path = policy_path;
}
}
package com.test.api.publication;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PublicationsDAOJdbcImpl implements PublicationsDAO{
static final Logger logger = LoggerFactory.getLogger(PublicationsDAOJdbcImpl.class.getName());
private DataSource _dataSource;
#Override
public void setDataSource(DataSource ds) {
// TODO Auto-generated method stub
}
#Override
public void close() {
// TODO Auto-generated method stub
}
#Override
public Publication getPublication(String policyPath) {
Publication ret = new Publication();
//TODO: do something
return ret;
}
}
package com.test.rest.publication;
import java.util.HashMap;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.test.api.publication.Publication;
import com.test.api.publication.PublicationsDAO;
import com.test.rest.error.UnknownResourceException;
#RestController
#RequestMapping("/pub")
public class PublicationController {
private static final Logger logger = LoggerFactory.getLogger(PublicationController.class);
#Autowired
#Qualifier("publicationsDAO")
private PublicationsDAO publicationsDAO;
/**********************************************************************************************************************
*
* #param policyPath
* #return
* #throws UnknownResourceException
*/
#RequestMapping(value = "/{policyPath}", method = RequestMethod.GET)
public Publication getByPolicyPath(#PathVariable String policyPath) throws UnknownResourceException{
logger.debug("policyPath=" + policyPath);
Publication ret = publicationsDAO.getPublication(policyPath);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("TEST1", null);
map.put("TEST2", new Integer(101));
map.put("TEST3", "QuinnZilla");
map.put("TEST4", new DateTime());
ret.setTokens(map);
return ret;
}
}
And I get the output result
{
"tokens": {
"TEST2": 101,
"TEST3": "QuinnZilla",
"TEST4": "2015-10-06T16:59:35.120Z",
"TEST1": null
},
"href": null,
"policyPath": null
}
We need to support XML and JSON output from a objects, I have a List which i display in json and xml format, the problem i am facing is it also shows the underlying class, below i am showing all part of codes starting with
output
domain objects
configuration &
controller
**XML Output**
"<**com.bookstore.Books**> Unwanted
<books>
<com.bookstore.Book>
<name>book0</name>
</com.bookstore.Book>
<com.bookstore.Book>
<name>book1</name>
</com.bookstore.Book>
</books>
</com.bookstore.Books>"
**JSON Output** Unwanted part is in bold
**"org.springframework.validation.BindingResult.books**"
:[{"isbn":"03601","authors":[{"autho
I have defind book class as
#XStreamAlias("book")
public class Book {....}
and Books
#XStreamAlias("books")
public class Books {...
List<Book> books;
The context settings are like this
<beans:bean id="xmlView"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<beans:constructor-arg>
<beans:bean class="org.springframework.oxm.xstream.XStreamMarshaller">
<beans:property name="autodetectAnnotations" value="true"/>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="jsonView"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
</beans:bean>
<beans:bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
</beans:bean>
The controller part is :
#RequestMapping(value = "/books/xml")
public ModelAndView getAllBooksXML() {
List<Book> books = bookService.getAllBooks();
ModelAndView mav =
new ModelAndView("xmlView", BindingResult.MODEL_KEY_PREFIX + "books", books);
return mav;
}
#RequestMapping(value = "/books/json")
public ModelAndView getAllBooksJson() {
List<Book> books = bookService.getAllBooks();
ModelAndView mav =
new ModelAndView("jsonView", BindingResult.MODEL_KEY_PREFIX + "books", books);
return mav;
}
Please let me know otherwie i will have t
i write a custom converter.
The code you provided seems to use XStream annotations while your spring configuration is configured to use jackson.
Have you tried the annotations supported by jackson?
https://github.com/FasterXML/jackson-annotations/wiki/JacksonAnnotations