前言
joda time是流行的java时间和日期框架,jackson是流行的json序列化框架,但是在默认情况下,jackson会将joda time序列化为较为复杂的形式,并不利于阅读,并且对象较大。
默认的序列化形式
当前日期的toJson后会变成如下的样子,内容很大。
{
"year": 2016,
"dayOfMonth": 29,
"dayOfWeek": 3,
"era": 1,
"dayOfYear": 181,
"weekyear": 2016,
"weekOfWeekyear": 26,
"millisOfDay": 51842473,
"monthOfYear": 6,
"hourOfDay": 14,
"minuteOfHour": 24,
"yearOfEra": 2016,
"yearOfCentury": 16,
"centuryOfEra": 20,
"secondOfDay": 51842,
"minuteOfDay": 864,
"secondOfMinute": 2,
"millisOfSecond": 473,
"millis": 1467181442473,
"zone": {
"uncachedZone": {
"cachable": true,
"fixed": false,
"id": "Asia/Shanghai"
},
"fixed": false,
"id": "Asia/Shanghai"
},
"chronology": {
"zone": {
"uncachedZone": {
"cachable": true,
"fixed": false,
"id": "Asia/Shanghai"
},
"fixed": false,
"id": "Asia/Shanghai"
}
},
"afterNow": false,
"beforeNow": true,
"equalNow": false
}
反序列化会直接报错,
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of org.joda.time.Chronology, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: java.io.StringReader@7d900ecf; line: 1, column: 442] (through reference chain: org.joda.time.DateTime["chronology"])
使用jackson的自定义的序列化方式
在stackoverflow上,有人回复说可以通过引用一下jar包来解决这个问题,但是在实践中发现,引用该jar包会使用会因为版本问题引发Error“java.lang.NoSuchFieldError:WRITE_DURATIONS_AS_TIMESTAMPS”,这种方式解决起来并不太方便。然后就考虑自己定义序列化与反序列化的方法
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.1.1</version>
</dependency>
使用jackson支持自定义某个类的序列化的方式
JsonSerializer是实现自定义序列化的类,其中
//序列化的时候可以将datetime序列化为字符串,更容易读
private static class DateTimeSerializer extends JsonSerializer<DateTime> {
@Override
public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString(value.toString(dateFormatter));
}
}
JsonDeserializer是自定义反序列化需要实现的类。
//返序列化将字符串转化为datetime
private static class DatetimeDeserializer extends JsonDeserializer<DateTime> {
@Override
public DateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String s = node.asText();
DateTime parse = DateTime.parse(s, dateFormatter);
return parse;
}
}
private static DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
//注册model,就可以使用了
SimpleModule module = new SimpleModule();
module.addSerializer(DateTime.class, new DateTimeSerializer());
module.addDeserializer(DateTime.class, new DatetimeDeserializer());
objectMapper.registerModule(module);
总结
jackson支持的这种扩展方式还是简单好用的,让框架有了好的扩展能力。