I'm working on a REST API in Spring MVC 3.2RC1.
I'm fetching a JPA entity with a org.joda.time.DateTime timestamp in it and let Spring serialise it into JSON using
@RequestMapping(value = "/foobar", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
Using the default Jackson2 settings in Spring as I've only added
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.1.1</version>
</dependency>
to my POM and let Spring wire it up itself.
The controller is generating:
"created":{"year":2012,"dayOfMonth":30,"dayOfWeek":5,"era":1,"dayOfYear":335,"weekOfWeekyear":48,"weekyear":2012,"monthOfYear":11,"yearOfEra":2012,"yearOfCentury":12,"centuryOfEra":20,"millisOfSecond":39,"millisOfDay":52684039,"secondOfMinute":4,"secondOfDay":52684,"minuteOfHour":38,"minuteOfDay":878,"hourOfDay":14,"millis":1354282684039,"zone":{"uncachedZone":{"cachable":true,"fixed":false,"id":"Europe/Stockholm"},"fixed":false,"id":"Europe/Stockholm"},"chronology":{"zone":{"uncachedZone":{"cachable":true,"fixed":false,"id":"Europe/Stockholm"},"fixed":false,"id":"Europe/Stockholm"}},"afterNow":false,"beforeNow":true,"equalNow":false}
But I would like it to be and ISO8601 date such as 2007-11-16T20:14:06.3Z (or with the offset).
My guess is that I need to access the ObjectMapper and set mapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); But how do I get access to the ObjectMapper when using
<mvc:annotation-driven />
P.S. I'm persisting the objects to PostgreSQL with JPA/Hibernate4 using UserType to get JodaTime support. D.S.
Update
The config below solves it for java.util.Date but still no dice for JodaTime.
<annotation-driven>
<message-converters>
<beans:bean
class="org.springframework.http.converter.StringHttpMessageConverter" />
<beans:bean
class="org.springframework.http.converter.ResourceHttpMessageConverter" />
<beans:bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="objectMapper">
<beans:bean
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true" p:simpleDateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSZ">
</beans:bean>
</beans:property>
</beans:bean>
</message-converters>
</annotation-driven>
Or, if you prefer doing your configuration in Java, it could look like this:
@Configuration
@EnableWebMvc
public class RestConfig extends WebMvcConfigurerAdapter {
private ObjectMapper objectMapper() {
Jackson2ObjectMapperFactoryBean bean = new Jackson2ObjectMapperFactoryBean();
bean.setIndentOutput(true);
bean.setSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
bean.afterPropertiesSet();
ObjectMapper objectMapper = bean.getObject();
objectMapper.registerModule(new JodaModule());
return objectMapper;
}
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper());
return converter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
}
I eventually got it working using jackson-datatype-joda:
Add another Maven dependency (match your Jackson version number):
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.version}</version>
</dependency>
Then register the JodaModule (which handles the conversion) to Jackson's ObjectMapper (here done in Spring, but you could create a helper class):
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
p:targetObject-ref="objectMapper" p:targetMethod="registerModule">
<property name="arguments">
<list><bean class="com.fasterxml.jackson.datatype.joda.JodaModule"/></list>
</property>
</bean>
(You'll need to give the ObjectMapper an id so that it can be referenced in this way).
The Hibernate module is also registered in this way: https://github.com/FasterXML/jackson-module-hibernate
Note that you need to set a (Simple)DateFormat as shown in the question, but disabling SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS
didn't seem to make any difference.
Just to sum up answers and post working solution for JodaTime serialization in Spring (tested on Spring 3.2)
spring-context.xml
<bean id="objectMapper"
class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true" p:simpleDateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSZ">
</bean>
<bean
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
p:targetObject-ref="objectMapper" p:targetMethod="registerModule">
<property name="arguments">
<list>
<bean class="com.fasterxml.jackson.datatype.joda.JodaModule" />
</list>
</property>
</bean>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean
class="org.springframework.http.converter.ResourceHttpMessageConverter" />
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Maven dependencies (com.fasterxml.jackson-version is 2.1.1)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${com.fasterxml.jackson-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${com.fasterxml.jackson-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${com.fasterxml.jackson-version}</version>
</dependency>
After this your JodaTime fields in ResponseBody will be automatically serialized in JSON as "createdDate" : "2013-01-18T15:15:36.365+02:00"
I was struggling with exactly the same b@#$d created by jackson from entity field with joda DayTime:
modifiedOn": {
"year": 2013,
"dayOfWeek": 6,
"era": 1,
"dayOfYear": 124,
"dayOfMonth": 4,
"weekOfWeekyear": 18,
"monthOfYear": 5,
"yearOfCentury": 13,
"centuryOfEra": 20,
"millisOfSecond": 0,
"millisOfDay": 81801000,
"secondOfMinute": 21,
"secondOfDay": 81801,
"minuteOfHour": 43,
"minuteOfDay": 1363,
"weekyear": 2013,
"yearOfEra": 2013,
"hourOfDay": 22,
"millis": 1367700201000,
"zone": {
"uncachedZone": {
"cachable": true,
"fixed": false,
"id": "Europe/Belgrade"
},
"fixed": false,
"id": "Europe/Belgrade"
},
"chronology": {
"zone": {
"uncachedZone": {
"cachable": true,
"fixed": false,
"id": "Europe/Belgrade"
},
"fixed": false,
"id": "Europe/Belgrade"
}
},
"afterNow": false,
"beforeNow": true,
"equalNow": false
}
As is mentioned here https://github.com/FasterXML/jackson-datatype-joda it is very easy with Jackson 2.0 but for newbie like me it was quite hard to figure out how to make it works, but finally found working piece of code:
Dependency in maven - that was simple
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.1.2</version>
</dependency>
and some code from FasterXML documentation
objectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
... but how to implement it? Here is the example - new class:
public class JodaObjectMapper extends ObjectMapper {
public JodaObjectMapper() {
super();
registerModule(new JodaModule());
}
}
And the last step - addition to spring.xml
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="net.jvw.JodaObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
So now let look on produced json
"modifiedOn": 1367701129075
finally something easy to deal with
From blog post http://vanwilgenburg.wordpress.com/2013/01/14/return-usable-joda-dates-in-json-with-jackson/
If somebody want to see more code of my entity class or controller - please ask in comment and I will add sufficient code to this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With