在运行时使用 Jackson 为多态添加 SubType 信息
Add SubType information at runtime using Jackson for polymorphism
我正在使用 Jackson 从 JSON 中解组多态类型。我正在使用类似于 this post 中示例 4 的 @JsonTypeInfo
、@JsonSubTypes
和 @JsonTypeName
注释。我的问题是,假设现在我需要其他人来扩展我的代码并在原始代码库之外添加第三个 class: public class Duck extends Animal
。我(或其他人)如何在不修改 public abstract Animal class
?
的源代码(注释)的情况下添加 SubType 信息
更新:
我被迫使用@JsonTypeName来解决POJO版本变更问题。例如:
package my.zoo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = Cat.class, name = "my.zoo.cat@1.0"),
@Type(value = Dog.class, name = "my.zoo.dog@1.0"),
@Type(value = Catv2.class, name = "my.zoo.cat@2.0")})
public abstract class Animal {
...
}
@JsonTypeName("my.zoo.cat@1.0")
public class Cat extends Animal {
...
}
@JsonTypeName("my.zoo.cat@2.0")
public class Catv2 extends Animal {
...
}
@JsonTypeName("my.zoo.dog@1.0")
public class Dog extends Animal {
...
}
// in another java package/project
package another.zoo;
import my.zoo.*;
@JsonTypeName("my.zoo.dog@2.0")
public class Dogv2 extends Animal {
...
}
现在我面临的问题是,如果不将 @Type(value = another.zoo.Dogv2.class, name = "my.zoo.Dog@2.0")})
添加到 Animal
class,我无法解组具有类型名称 "my.zoo.dog@2.0" 的 JSON .所以用注释来做这件事显然是不可能的。有没有办法在运行时执行此操作?
更新 2:
我刚刚发现 this SO question 与 same/similar 用例。我在这里担心的是,使用注释会阻止人们 extending/implementing 你的基地 class/interface。我想要一种方法来保持我的基础的可扩展性 class/interface 并确保我的(非)编组逻辑将适用于未来的具体类型。
不要使用 @JsonSubTypes
。使用 @JsonTypeInfo#use
with JsonTypeInfo.Id.CLASS
来识别序列化和反序列化的类型。
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class Animal { /* whatever */ }
Jackson 然后将存储完全限定名称以序列化对象并再次使用它来确定反序列化的目标 class。
您必须确保子 class 中的 none 有一个名为 type
的 属性。
可以使用 @JsonSubTypes
来完成这项工作,但它涉及混合,不是一个非常易于维护的解决方案。
我最终使用 Reflections 库查找 Animal
class 的所有子类型,并使用 mapper.registerSubtypes(Class<?>... classes)
方法注册 JsonSubTypes。
我正在使用 Jackson 从 JSON 中解组多态类型。我正在使用类似于 this post 中示例 4 的 @JsonTypeInfo
、@JsonSubTypes
和 @JsonTypeName
注释。我的问题是,假设现在我需要其他人来扩展我的代码并在原始代码库之外添加第三个 class: public class Duck extends Animal
。我(或其他人)如何在不修改 public abstract Animal class
?
更新:
我被迫使用@JsonTypeName来解决POJO版本变更问题。例如:
package my.zoo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = Cat.class, name = "my.zoo.cat@1.0"),
@Type(value = Dog.class, name = "my.zoo.dog@1.0"),
@Type(value = Catv2.class, name = "my.zoo.cat@2.0")})
public abstract class Animal {
...
}
@JsonTypeName("my.zoo.cat@1.0")
public class Cat extends Animal {
...
}
@JsonTypeName("my.zoo.cat@2.0")
public class Catv2 extends Animal {
...
}
@JsonTypeName("my.zoo.dog@1.0")
public class Dog extends Animal {
...
}
// in another java package/project
package another.zoo;
import my.zoo.*;
@JsonTypeName("my.zoo.dog@2.0")
public class Dogv2 extends Animal {
...
}
现在我面临的问题是,如果不将 @Type(value = another.zoo.Dogv2.class, name = "my.zoo.Dog@2.0")})
添加到 Animal
class,我无法解组具有类型名称 "my.zoo.dog@2.0" 的 JSON .所以用注释来做这件事显然是不可能的。有没有办法在运行时执行此操作?
更新 2:
我刚刚发现 this SO question 与 same/similar 用例。我在这里担心的是,使用注释会阻止人们 extending/implementing 你的基地 class/interface。我想要一种方法来保持我的基础的可扩展性 class/interface 并确保我的(非)编组逻辑将适用于未来的具体类型。
不要使用 @JsonSubTypes
。使用 @JsonTypeInfo#use
with JsonTypeInfo.Id.CLASS
来识别序列化和反序列化的类型。
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class Animal { /* whatever */ }
Jackson 然后将存储完全限定名称以序列化对象并再次使用它来确定反序列化的目标 class。
您必须确保子 class 中的 none 有一个名为 type
的 属性。
可以使用 @JsonSubTypes
来完成这项工作,但它涉及混合,不是一个非常易于维护的解决方案。
我最终使用 Reflections 库查找 Animal
class 的所有子类型,并使用 mapper.registerSubtypes(Class<?>... classes)
方法注册 JsonSubTypes。