在 Jackson 中以编程方式设置类型鉴别器

Set Type Discriminator programmatically in Jackson

对于多态反序列化,Jackson 的 ObjectMapper 想知道:

  1. 需要考虑哪些亚型
  2. 如何决定,使用哪个子类型

有一些标准方法,使用完全限定的 class 名称和某些保留的 JSON 属性,因此 Jackson 无需进一步配置就可以扣除这些东西。

另一种常见的方法是,通过向基本类型添加注释 @JsonTypeInfo@JsonSubtypes 来为 Jackson 提供必要的信息。然而,这意味着,当添加新的子类型时,必须修改声明基础 class 的文件。

也可以在运行时通过 objectMapper.registerSubtypes(...).

以编程方式将子类型注册到 ObjectMapper

现在我正在寻找一种方法来在运行时以编程方式提供来自@JsonTypeInfo 的信息,而不使用该注释。

类似 objectMapper.addTypeInfo(new TypeInfo(BaseType.class, PROPERTY, "myPropertyName", NAME); 这样我就可以对在另一个项目中声明的类型使用多态反序列化,该项目对 Jackson 或其任何注释一无所知。

要在不修改实际 class 的情况下注册 @JsonTypeInfo,您必须使用这样的混合:

// actual base type that we don't want to or can't modfiy 
// because it is in a different module / 3rd party
public class BaseType {  
    ...
}

// mixin for BaseType to define @JsonTypeInfo
// this can be in a completely different package / module
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY, property = "type")
public abstract class BaseTypeMixIn {
}

必须为 ObjectMapper 手动注册 mixin:

objectMapper.addMixIn(BaseType.class, BaseTypeMixIn.class);

BaseType 现在有效地具有来自混入的 @JsonTypeInfo。 jackson 中的 Mixin 是解决“How do I annotate a class that I can't modify”问题的一般解决方案。

对于子类型,可以使用 ObjectMapper.registerSubtypes 注册类型信息或通过使用 @JsonSubtypes 注释混合。在这种情况下,我更喜欢在没有注释的情况下进行操作,因为如果不同的模块具有基本类型的不同子类型,它也可以工作。注册多个 mixin 很可能不起作用。

public class SubTypeA extends BaseType {
   ...
}

public class SubTypeB extends BaseType {
    ...
}

在 ObjectMapper 中注册:

objectMapper.registerSubtypes(
   new NamedType(SubTypeA.class, "A"), 
   new NamedType(SubTypeB.class, "B"));