首页 > 解决方案 > 在 Jackson 中以编程方式设置类型鉴别器

问题描述

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

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

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

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

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

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

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

标签: javajacksonjackson-databind

解决方案


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

// 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从 mixin 中获取。jackson 中的 Mixin 是“如何注释我无法修改的类”问题的一般解决方案。

对于子类型,可以使用 注册ObjectMapper.registerSubtypes或通过使用 注释 mixin来注册类型信息@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"));

推荐阅读