Using Spring RestControllers with Jackson JSON parsing backend, with AngularJS on front end. I'm looking for an efficient way to have Jackson serialize an Instant as the epoch milliseconds for subsequent convenient usage with JavaScript code. (On the browser side I wish to feed the epoch ms through Angular's Date Filter: {{myInstantVal | date:'short' }}
for my desired date format.)
On the Java side, the getter that Jackson would use is simply:
public Instant getMyInstantVal() { return myInstantVal; }
Serialization wouldn't work as-is, because the jackson-datatype-jsr310 doesn't return Epoch milliseconds by default for an Instant. I looked at adding @JsonFormat to the above getter to morph the Instant into something the front-end can use, but it suffers from two problems: (1) the pattern I can supply it is apparently limited to SimpleDateFormat which doesn't provide an "epoch milliseconds" option, and (2) when I tried to send the Instant as a formatted date to the browser instead, Jackson throws an exception because the @JsonFormat annotation requires a TimeZone attribute for Instants, something I don't wish to hardcode as it would vary from user to user.
My solution so far (and it's working fine) is to create a replacement getter using @JsonGetter, which causes Jackson to use this method instead to serialize myInstantVal
:
@JsonGetter("myInstantVal")
public long getMyInstantValEpoch() {
return myInstantVal.toEpochMilli();
}
Is this the proper way of doing this? Or is there a nice annotation I'm missing that I can put on getMyInstantVal() so I won't have to create these additional methods?
In order to correct deserialize a Date field, you need to do two things: 1) Create a custom deserializer by extending StdDeserializer<T> class and override its deserialize(JsonParser jsonparser, DeserializationContext context) method. This method should return a Date if we are using this to parse a date field in JSON.
It's important to note that Jackson will serialize the Date to a timestamp format by default (number of milliseconds since January 1st, 1970, UTC).
XML Serialization and Deserialization with Jackson This short tutorial shows how the Jackson library can be used to serialize Java object to XML and deserialize them back to objects.
You just need to read the README that you linked to. Emphasis mine:
Most JSR-310 types are serialized as numbers (integers or decimals as appropriate) if the SerializationFeature#WRITE_DATES_AS_TIMESTAMPS feature is enabled, and otherwise are serialized in standard ISO-8601 string representation.
[...]
Granularity of timestamps is controlled through the companion features SerializationFeature#WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS and DeserializationFeature#READ_DATE_TIMESTAMPS_AS_NANOSECONDS. For serialization, timestamps are written as fractional numbers (decimals), where the number is seconds and the decimal is fractional seconds, if WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS is enabled (it is by default), with resolution as fine as nanoseconds depending on the underlying JDK implementation. If WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS is disabled, timestamps are written as a whole number of milliseconds.
Adding on to JB's answer, to override Spring MVC's default JSON parser to strip away the nanoseconds from Instant (and other Java 8 date objects that have them):
In the mvc:annotation-driven element, specify that you will be overriding the default JSON message converter:
<mvc:annotation-driven validator="beanValidator">
<mvc:message-converters register-defaults="true">
<beans:ref bean="jsonConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
(register-defaults above is true by default and most probably what you'll want to keep the other converters configured by Spring as-is).
Override MappingJackson2HttpMessageConverter as follows:
<beans:bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<beans:property name="objectMapper">
<beans:bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<beans:property name="featuresToDisable">
<beans:array>
<util:constant static-field="com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS"/>
</beans:array>
</beans:property>
</beans:bean>
</beans:property>
Step #1 is important as Spring MVC will otherwise ignore the configured MJ2HMC object in favor of its own default one.
partial H/T this SO post.
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