转载 

Custom Json Serializer and Deserializer for Joda datetime objects

分类:    722人阅读    IT小君  2017-05-22 14:16

package cn.eshifu.sales.payment;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Created by YouGuessWho on 2017/5/18.
 */
public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException, JsonProcessingException {
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        arg1.writeString(arg0.format(format));
    }
}

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 = LocalDateTime.now();
      ...

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:

{"asDefault":{"era":1,"dayOfMonth":24,"dayOfWeek":6,"dayOfYear":24,"year":2015,"yearOfEra":2015,...}

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 = LocalDateTime.now();

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

{"asArray":[2015,1,24,10,31,3,379]}

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:

{"custom":
     {"date":"2015-01-24",
      "time":"10:31:03"
}

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 = LocalDateTime.now();

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() {
            super(LocalDateTime.class);
      }

      protected CustomLocalDateTimeSerializer(Class<LocalDateTime> t) {
            super(t);
      }

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

Class CustomLocalDateTimeDeserializer

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

      public CustomLocalDateTimeDeserializer() {
            super(LocalDateTime.class);
      }

      protected LocalDateTimeDeserializerMongoDb(Class<?> vc) {
            super(vc);
      }

      @Override
      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) {
                     break;
                }
           }
           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.

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

 工具推荐 更多»