Imtiaz Mirza Imtiaz Mirza - 5 months ago 95x
Java Question

Jersey consuming/ parsing Java 8 date time

This is my user class, and I to save ISO compliant date time in my database.

public class User {

private String id;

private String email;

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime loginDate;


Here is my Jersey controller:


public Response create( User user) {

Map<Object, Object> apiResponse = new HashMap<Object, Object>();
Map<Object, Object> response = new HashMap<Object, Object>();

user = (User) userService.create(user);


How can can I consume a datetime format like this one in jersey? Is it possible to send a datatime
and create Java 8 date time object automatically?

"email" : ""
"loginDate" : "2015-04-17T06:06:51.465Z"



I was using Spring boot jersey, and had other jsr packages


So I removed all the packages except from spring-boot-jersey package.
use this annotation for LocalDateTime

@JsonDeserialize(using = LocalDateTimeDeserializer.class)

This way I can consume ISODate and save ISODate() to mongodb and produce full formated mongodb LocalDateTime to frontend.

Problem solved.


Couple options I see...

Option 1:

Assuming you have JAXB annotation support with Jackson as the JSON provider...

You could use an XmlAdapter. For example

public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {

    public LocalDateTime unmarshal(String dateString) throws Exception {
        Instant instant = Instant.parse(dateString);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return dateTime;

    public String marshal(LocalDateTime dateTime) throws Exception {
        Instant instant = dateTime.toInstant(ZoneOffset.UTC);
        return DateTimeFormatter.ISO_INSTANT.format(instant);

See the Instant API for more information.

Then you can just annotate the field/property with the adapter

private LocalDateTime loginDate;

You could also declare the annotation at the package level, so that all uses in the package will use the adapter, without the need to annotate. You do so in a file named put inside the package

    @XmlJavaTypeAdapter(type = LocalDateTime.class, 
                        value = LocalDateTimeAdapter.class)
package thepackage.of.the.models;

import java.time.LocalDateTime;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;

Option 2:

Use the Jackson APIs directly. Meaning, use a JsonDeserializer and JsonSerializer. For example

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    public LocalDateTime deserialize(JsonParser jp, 
            DeserializationContext dc) throws IOException, JsonProcessingException {
        ObjectCodec codec = jp.getCodec();
        TextNode node = (TextNode)codec.readTree(jp);
        String dateString = node.textValue();
        Instant instant = Instant.parse(dateString);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return dateTime;

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

    public void serialize(LocalDateTime dateTime, JsonGenerator jg, 
            SerializerProvider sp) throws IOException, JsonProcessingException {
        Instant instant = dateTime.toInstant(ZoneOffset.UTC);

You can apply this at the field/property level

@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
public LocalDateTime loginDate; 

Or at the ObjectMapper level (so you don't need to annotate everywhere)

public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

    final ObjectMapper mapper = new ObjectMapper();

    public ObjectMapperContextResolver() {
        SimpleModule module = new SimpleModule();
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        // add JAXB annotation support if required
        mapper.registerModule(new JaxbAnnotationModule());

    public ObjectMapper getContext(Class<?> type) {
        return mapper;

Basically what happens, is that the MessageBodyWriter/MessageBodyReader used for ummarshalling/marshalling, will call the getContext method to get the ObjectMapper


  • The above solutions will parse from the format 2007-12-03T10:15:30.00Z, as documented in Instant.parse, and will serialize to the same format, as documented in DateTimeFormatter.ISO_INSTANT

  • The above is also assuming you are using Jackson as the Serializer. I used the below dependency (with Jersey 2.16) to test


    The dependency uses a JacksonJaxbJsonProvider for JAXB annotation support. If you are using a lower version of Jersey like 1.x, the jersey-json dependency should offer JAXB annotation support, if you enable the POJO mapping feature. Alternatively for Jersey 1.x, if you want to use Jackson 2, you can use this dependency


    which is actually what is used by jersey-media-json-jackson. So you could explicitly register the JacksonJaxbJsonProvider, or add the Jackson package (com.fasterxml.jackson.jaxrs.json) to list packages to scan


See Also: