已注册JodaModule仍无法序列化org.joda.time.Days的问题求助
问题:Joda Time的Days类型无法被Jackson序列化
环境依赖
使用Joda Time 2.10.14与Jackson2 2.18.3,依赖如下:
jackson-core-2.18.3.jar jackson-databind-2.18.3.jar jackson-datatype-joda-2.18.3.jar joda-time-2.10.14.jar
复现代码
已注册JodaModule但仍抛出序列化异常,代码示例:
public static void main(String[] args) throws JsonProcessingException { DateTime dateTime = new DateTime(); Days days = Days.days(1); Map<String, Object> map = new HashMap<>(); map.put("dateTime", dateTime); map.put("days", days); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JodaModule()); String json = objectMapper.writeValueAsString(map); System.out.println(json); }
异常信息
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Joda date/time type `org.joda.time.Days` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-joda" to enable handling (through reference chain: java.util.HashMap["days"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1340) at com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer.serialize(UnsupportedTypeSerializer.java:35) at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:808) at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:764) at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:720) at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:35) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:502) at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:341) at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4819) at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:4060) at azkaban.utils.JSONUtils.main(JSONUtils.java:96)
经查看JodaModule源码,确认其未内置Days类型的序列化器,可通过以下方式解决:
解决方案
方案1:自定义序列化/反序列化器
针对Days类型编写专属的序列化和反序列化逻辑,注册到ObjectMapper:
// 序列化器:将Days转为整数 public class DaysSerializer extends JsonSerializer<Days> { @Override public void serialize(Days days, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeNumber(days.getDays()); } } // 反序列化器:从整数还原为Days public class DaysDeserializer extends JsonDeserializer<Days> { @Override public Days deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { return Days.days(p.getIntValue()); } }
注册到ObjectMapper:
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JodaModule()); SimpleModule daysModule = new SimpleModule(); daysModule.addSerializer(Days.class, new DaysSerializer()); daysModule.addDeserializer(Days.class, new DaysDeserializer()); objectMapper.registerModule(daysModule);
方案2:手动转换为基础类型(仅序列化场景)
如果只需要序列化,无需反序列化,可在存入Map前直接将Days转为整数:
map.put("days", days.getDays());
方案3:使用Jackson Mixin特性
通过Mixin为Days类添加序列化注解,指定用getDays()方法的返回值作为序列化结果:
public abstract class DaysMixin { @JsonValue public abstract int getDays(); }
注册Mixin到ObjectMapper:
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JodaModule()); objectMapper.addMixIn(Days.class, DaysMixin.class);
内容的提问来源于stack exchange,提问作者hehe
相关产品推荐
相关产品推荐

