如何让ObjectMapper根据JSON的type字段创建对应子类实例?
Jackson ObjectMapper 根据type字段反序列化子类实例
问题场景
现有如下Java类结构:
public class SomeClass { ArrayList<BaseClass> list; } public class BaseClass { String id; String type; } public class MyClass1 extends BaseClass{ } public class MyClass2 extends BaseClass{ }
对应的JSON数据:
{ "list": [ { "id": "1", "type": "MyClass1" }, { "id": "2", "type": "MyClass2" }, { "id": "3", "type": "MyClass1" } ] }
需要让ObjectMapper根据type字段的值,将列表中的对象反序列化为对应的子类(MyClass1/MyClass2)而非父类BaseClass实例。
解决方案:使用Jackson类型注解
这是最直接的实现方式,通过在父类BaseClass上添加Jackson的类型识别注解,指定用type字段判断要实例化的子类:
修改BaseClass类,添加@JsonTypeInfo和@JsonSubTypes注解:
import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type", // 指定用来判断类型的字段 visible = true // 保留type字段的值,不会被Jackson自动处理 ) @JsonSubTypes({ @JsonSubTypes.Type(value = MyClass1.class, name = "MyClass1"), @JsonSubTypes.Type(value = MyClass2.class, name = "MyClass2") }) public class BaseClass { String id; String type; // 需添加getter/setter,Jackson依赖它们访问字段 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
验证反序列化
之后正常使用ObjectMapper反序列化即可,Jackson会自动根据type字段创建对应子类实例:
import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { String json = "{\"list\":[{\"id\":\"1\",\"type\":\"MyClass1\"},{\"id\":\"2\",\"type\":\"MyClass2\"},{\"id\":\"3\",\"type\":\"MyClass1\"}]}"; ObjectMapper mapper = new ObjectMapper(); SomeClass someClass = mapper.readValue(json, SomeClass.class); // 验证每个元素的类型 for (BaseClass item : someClass.list) { System.out.println(item.getClass().getSimpleName()); } // 输出:MyClass1、MyClass2、MyClass1 } }
注意事项
- 必须确保
BaseClass、MyClass1、MyClass2有公共无参构造方法,Jackson默认依赖它实例化对象。 - 如果
type字段值和子类名称不一致,可在@JsonSubTypes.Type的name属性指定对应关系,比如name = "TYPE1"对应MyClass1.class。 - 若不想用注解,也可自定义
TypeResolverBuilder或DeserializationProblemHandler实现类型判断,但注解方式最简洁。
内容的提问来源于stack exchange,提问作者Bitlejuce Do
相关产品推荐
相关产品推荐

