Custom Json Serializer and Deserializer for Joda datetime objects

This post demonstrates how to add custom Json serializer and deserializer classes for Joda datetime objects when used with Jackson JSON processor. I use LocalDateTime in the examples here but the same approach applies to other joda date(time) classes.

Default Serialization

By default, Jackson serializes the whole joda object as is. For example, consider the following object:

 public class ExampleDto {
      private LocalDateTime asDefault =;

Serializing it with Jackson with

import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper(); 
String json = mapper.writeValueAsString(new ExampleDto());

will return something like below in the json string:


Not really useful

LocalDateTimeSerializer / LocalDateTimeDeserializer

Jackson provides an alternative for handling Joda objects. For example

public class ExampleDto {
       @JsonSerialize(using = LocalDateTimeSerializer.class)
       @JsonDeserialize(using = LocalDateTimeDeserializer.class)
       private LocalDateTime asArray =;

This will return an array of integer representing the datetime in the json string, for example:


Custom Serializer and Deserializer

It is also possible to customize the output json by adding custom serialization and deserialization classes. For example, to generate json like:


The above format is useful when you have to persist the Json in NoSQL database such as MongoDB for datetime queries. To achieve this, first modify the @JsonSerialize and @JsonDeserialize annotations with the names of custom classes and then implements the custom classes:

public class ExampleDomain {
      @JsonSerialize(using = CustomLocalDateTimeSerializer.class)
      @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
      private LocalDateTime custom =;

Class CustomLocalDateTimeSerializer

public class CustomLocalDateTimeSerializer extends StdScalarSerializer<LocalDateTime> {

      private final static DateTimeFormatter DATE_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd");
      private final static DateTimeFormatter TIME_FORMAT = DateTimeFormat.forPattern("HH:mm:ss");
      public CustomLocalDateTimeSerializer() {

      protected CustomLocalDateTimeSerializer(Class<LocalDateTime> t) {

      public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider prov      ider) throws IOException, JsonProcessingException {
            jgen.writeStringField("date", DATE_FORMAT.print(value));
            jgen.writeStringField("time", TIME_FORMAT.print(value));

Class CustomLocalDateTimeDeserializer

public class CustomLocalDateTimeDeserializer extends StdScalarDeserializer<LocalDateTime> {
      private final static DateTimeFormatter DATETIME_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

      public CustomLocalDateTimeDeserializer() {

      protected LocalDateTimeDeserializerMongoDb(Class<?> vc) {

      public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
           String dateStr = null;
           String timeStr = null;
           String fieldName = null;
           while (jp.hasCurrentToken()) {
                JsonToken token = jp.nextToken();
                if (token == JsonToken.FIELD_NAME) {
                     fieldName = jp.getCurrentName();
                } else if (token == JsonToken.VALUE_STRING) {
                     if (StringUtils.equals(fieldName, "date")) {
                          dateStr = jp.getValueAsString();
                     } else if (StringUtils.equals(fieldName, "time")) {
                          timeStr = jp.getValueAsString();
                     } else {
                          throw new JsonParseException("Unexpected field name", jp.getTokenLocation());
                } else if (token == JsonToken.END_OBJECT) {
           if (dateStr != null && timeStr != null) {
                  LocalDateTime dateTime = LocalDateTime.parse(dateStr + " " + timeStr, DATETIME_FORMAT);
                  return dateTime;
         return null;

Note how the JsonParser is used in the deserializer. Also, the datetime formats used in the serializer and deserializer must match.