0

How can I get MOXy to unmarshal JSON into LocalDate and LocalDateTime?

I've got an @GET method which produces a sample instance with three fields of types LocalDate, LocalDateTime and Date, respectively.

Hitting that endpoint, I get:

{
    "localDate": "2017-07-11",
    "localDateTime": "2017-07-11T10:11:10.817",
    "date": "2017-07-11T10:11:10.817+02:00"
}

I then POST the above data to my @POST method, which simply returns the data again:

{
    "date": "2017-07-11T10:11:10.817+02:00"
}

As you can see, both localDate and localDateTime are lost in the process, because MOXy does not initialize those two fields.

What gives? MOXy seems to support serialization of these types, but not deserialization?

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

@Path("/test/date")
public class DateTest {
    public static class Data {
        public LocalDate localDate;
        public LocalDateTime localDateTime;
        public Date date;
    }

    @GET
    @Path("roundtrip")
    public Response roundtrip() {
        Data sample = getSample();
        return roundtrip(sample);
    }

    @POST
    @Path("roundtrip")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response roundtrip(Data t) {
        return Response.status(Response.Status.OK).entity(t).build();
    }

    protected Data getSample() {
        final Data data = new Data();
        data.localDate = LocalDate.now();
        data.localDateTime = LocalDateTime.now();
        data.date = new Date();
        return data;
    }
}

Moxy version: jersey-media-moxy-2.25.1

phant0m
  • 16,595
  • 5
  • 50
  • 82
  • 1
    Is it really "serializing" (in the more common sense) or is it simply calling toString()?. There's a difference. Until MOXy/JAXB actually supports Java8 time, you'll probably need to [use an XMLAdapter](http://blog.bdoughan.com/2011/05/jaxb-and-joda-time-dates-and-times.html). Or you can use Jackson instead of MOXy, and [use its Java8 time support](https://stackoverflow.com/a/28803634/2587435) – Paul Samsotha Jul 11 '17 at 08:35
  • @peeskillet I didn't think of this possibility. I read [your post](https://stackoverflow.com/a/26825079/383124) and understood that to mean that it was supported. – phant0m Jul 11 '17 at 08:40
  • In that post I actually gave both examples of what I mentioned as solutions in my previous comment (i.e. use an adapter or switch to Jackson) – Paul Samsotha Jul 11 '17 at 08:42
  • Actually, I think I need to update the post. I probably tested only using the serialization :-D – Paul Samsotha Jul 11 '17 at 08:44
  • @peeskillet the XMLAdapter really solves this problem. In addition you may then specify the format how the LocalDateTime will be marshalled/unmarshalled. +1 – gabriel Sep 20 '17 at 13:11

1 Answers1

2

According to peeskillet's suggestion I implemented the following adapter class:

public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime>{

  private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

  @Override
  public String marshal(LocalDateTime localDateTime) throws Exception {
    return localDateTime.format(DTF);
  }

  @Override
  public LocalDateTime unmarshal(String string) throws Exception {
    return LocalDateTime.parse(string, DTF);
  }

}

In addition, I created package-info.java in the same package where my classes for MOXy and the adapter (in a subpackage) are located with the following content:

@XmlJavaTypeAdapters({
  @XmlJavaTypeAdapter(type=LocalDateTime.class,
      value=LocalDateTimeAdapter.class)
})
package api;

import java.time.LocalDateTime;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;

import api.adapter.LocalDateTimeAdapter;

Thus, marshalling and unmarshalling works without problems. And with DTF you can specify the format that shall be applied.

gabriel
  • 347
  • 3
  • 18