如何使用Jackson数据绑定序列化java.time类的类型信息?
我目前正在将一个遗留应用程序从java.util.Date类移植到java.time API。我使用默认类型来保留类型信息。 由于java.time类被标记为final,Jackson不会在JSON输出中添加任何类型信息。这基本上是可以的,但在这种情况下: 我有一个类,它有一个类型对象的成员,可以包含各种数据类型。它是在运行时填充的,所以我不知道它将提前包含哪种数据类型。然后将其序列化并发送到客户端,客户端将其反序列化并使用如何使用Jackson数据绑定序列化java.time类的类型信息?,java,json,jackson,java-time,jackson-databind,Java,Json,Jackson,Java Time,Jackson Databind,我目前正在将一个遗留应用程序从java.util.Date类移植到java.time API。我使用默认类型来保留类型信息。 由于java.time类被标记为final,Jackson不会在JSON输出中添加任何类型信息。这基本上是可以的,但在这种情况下: 我有一个类,它有一个类型对象的成员,可以包含各种数据类型。它是在运行时填充的,所以我不知道它将提前包含哪种数据类型。然后将其序列化并发送到客户端,客户端将其反序列化并使用instanceof检查数据类型。 这在java.util.Date中运
instanceof
检查数据类型。
这在java.util.Date
中运行良好,因为类型已序列化ZonedDateTime
,因为没有类型信息,将反序列化为字符串,这将导致后面的代码中出现错误
我已经阅读了关于不同的DefaultTyping
-设置的Jackson文档,但是添加最多类型信息的选项似乎是NON_FINAL
,这仍然会导致此问题
我还尝试编写自己的序列化程序并覆盖serializeWithType
-方法,但它从未被调用
我可以编写一个包含ZoneDateTime的非最终包装类,但如果可能的话,我希望避免这种情况
以下是我的ObjectMapper配置:
ObjectMapper myMapper=new ObjectMapper()
.enable(MapperFeature.AUTO\u DETECT\u创建者)
.enable(MapperFeature.AUTO\u DETECT\u字段)
.enable(序列化功能。使用区域ID写入日期)
.disable(MapperFeature.AUTO\u DETECT\u getter)
.disable(MapperFeature.AUTO\u DETECT\u SETTERS)
.disable(MapperFeature.USE_注释)
.disable(序列化功能。将日期写入时间戳)
.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setVisibility(PropertyAccessor.ALL、JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD,JsonAutoDetect.Visibility.ANY)
.registerModule(新的JavaTimeModule());
这就是我现在得到的结果:
"2019-08-02T16:03:41.988+02:00[Europe/Berlin]"
这就是我想要的:
["java.time.ZonedDateTime", "2019-08-02T16:03:41.988+02:00[Europe/Berlin]"]
这可以通过为Jackson提供一个getter方法来实现,该方法可以生成所需的输出。如果实例变量有getter方法,可以告诉Jackson忽略它:
public class MyBean
{
private Object obj;
// tell jackson to ignore standard getter method
@JsonIgnore
public Object getObj() {
return obj;
}
// this is the method that jackson will call during serialization
@JsonProperty("obj")
public String[] getObjForJson() {
return new String[] {
obj.getClass().getName(),
obj.toString()
};
}
}
试验方法
public static void main(String[] args) {
MyBean myBean = new MyBean();
myBean.obj = ZonedDateTime.now();
ObjectMapper mapper = new ObjectMapper();
try {
mapper.writeValue(System.out, myBean);
} catch (Exception e) {
e.printStackTrace();
}
}
输出:
{"obj":["java.time.ZonedDateTime","2019-08-06T11:09:30.467+03:00[Asia/Jerusalem]"]}
由于另一个答案不适用于我的情况,我实施了一个变通方法。它不是很优雅,如果有人有更好的解决方案,我会删除它,但目前它是有效的 我使用泛型类型实现了以下包装器类:
public class FinalClassContainer <T> {
private T containedObject;
public FinalClassContainer(T obj)
{
this.containedObject = obj;
}
public T getContainedClass()
{
return containedObject;
}
}
这允许我在客户端调用
container.getContainedClass()
,它返回正确类型的对象。这不是我的主字段,所以只需询问:您在使用吗?如果你这样做会有帮助吗?我已经包括并注册了jackson-datatype-jsr310
。我现在也尝试了包含jackson-datatype-jdk8
,但没有任何区别。遗憾的是,这在我的情况下不起作用,因为可以保存在成员变量中的其他对象可能需要进一步序列化。这个答案为问题提供了一个解决方案。也许您需要澄清问题中的完整要求。
[
"com.test.FinalClassContainer",
{
"containedObject": [
"java.time.ZonedDateTime",
"2019-08-08T11:22:00.996+02:00[Europe/Berlin]"
]
}
]