Apache Johnzon JSON library and Javascript date


By default Apache Johnzon JSON-Java mapper uses the pattern “yyyyMMddHHmmssZ” for Dates. The good thing about this pattern is that it is fast enough for most cases. However, its drawback is not as common as the ISO8601 format of the RFC822.

The solution is quite simple.

By writing your own adapter you’ll solve it quickly. In other words, we need to implement this:

import org.apache.johnzon.mapper.Converter;
import java.util.Date;

public class JavascriptDate implements Converter<Date> {
    @Override
    public String toString(final Date instance) {
        // TODO
    }

    @Override
    public Date fromString(final String text) {
        // TODO
    }
}

Now, I guess you start to think about which pattern to use with a SimpleDateFormat. You surely thought about something like “yyyy-MM-dd’T’HH:mm:ssZ”. There is an easier solution, reusing what JAXB provides : the DatatypeConverter!

With this, our implementation becomes quite easy:

import org.apache.johnzon.mapper.Converter;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.bind.DatatypeConverter;

public class JavascriptDate implements Converter<Date> {
    @Override
    public String toString(final Date instance) {
        final Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(instance);
        return DatatypeConverter.printDateTime(cal);
    }

    @Override
    public Date fromString(final String text) {
        return DatatypeConverter.parseDateTime(text).getTime();
    }
}

Now, we simply need to wire it in Jonhzon:

public class MyJsonObject {
    private Date date;

    // for deserialization
    @JohnzonConverter(JavascriptDate.class)
    public void setDate(final Date date) {
        this.date = date;
    }

    // for serialization
    @JohnzonConverter(JavascriptDate.class)
    public Date getDate() {
        return date;
    }
}

If you want to set it globally, then do it on the MapperBuilder:

new MapperBuilder()
  .addPropertyEditor(Date.class, new JavascriptDate())
  .build();

And if you want to set it on field, then configure the accessMode in the builder to both (ie field and methods) or field:

new MapperBuilder()
  .setAccessModeName("field")
  .build();

If you use TomEE, create a WEB-INF/resources.xml with:

<?xml version="1.0"?>
<resources>
  <Service id="johnzon" class-name="org.apache.johnzon.jaxrs.ConfigurableJohnzonProvider">
    accessModeName = field
  </Service>
</resources>

and create a WEB-INF/openejb-jar.xml with:

<?xml version="1.0" encoding="UTF-8"?>
<openejb-jar>
  <pojo-deployment class-name="com.tomitribe.team.time.report.resource.TimeReportApplication">
    <properties>
      cxf.jaxrs.skip-provider-scanning = true
      cxf.jaxrs.providers = johnzon,org.apache.openejb.server.cxf.rs.EJBAccessExceptionMapper
    </properties>
  </pojo-deployment>
</openejb-jar>

Side note: cxf.jaxrs.skip-provider-scanning is optional but it ignores providers scanning which is often good to control its application. As concerns EJBAccessExceptionMapper, it maps a security exception coming from an EJB to a standard HTTP 403. If you don’t use EJB just ignore it.

The final note is that Java 8 introduced ISO8601 DateTimeFormatters which are very good candidates for this kind of implementation.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s