如何用Jackson处理含父类与子类的JSON数组生成List<Car>?
解决方案:Jackson多态反序列化实现混合类型List
要解决这个问题,核心是让Jackson在反序列化时能识别JSON对应的具体子类类型,下面是两种可行的实现方案:
方案一:通过类型注解配置(推荐)
这种方式需要在父类上添加多态注解,同时让Web服务返回的JSON包含类型标记字段,是最规范可靠的做法。
1. 给父类Car添加多态注解
在Car类上添加@JsonTypeInfo和@JsonSubTypes,明确类型识别规则和子类映射:
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonSubTypes; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" // 指定JSON中用来标记类型的字段名 ) @JsonSubTypes({ @JsonSubTypes.Type(value = Car.class, name = "car"), @JsonSubTypes.Type(value = Truck.class, name = "truck") }) public class Car { private String brand; private String model; // 构造方法、getter/setter省略 }
2. 确保JSON包含类型标记
Web服务返回的JSON数组中,每个对象需要携带type字段,用来区分是Car还是Truck:
[ { "type": "car", "brand": "Toyota", "model": "Camry" }, { "type": "truck", "brand": "Ford", "model": "F-150", "maxLoad": 5000, "clearance": 12 } ]
3. 正常反序列化
直接用ObjectMapper反序列化为List<Car>即可,Jackson会自动识别类型并生成对应实例:
import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; public class TestDeserialization { public static void main(String[] args) throws Exception { String jsonStr = "[...]"; // 替换为实际JSON字符串 ObjectMapper mapper = new ObjectMapper(); List<Car> carList = mapper.readValue( jsonStr, mapper.getTypeFactory().constructCollectionType(List.class, Car.class) ); // 验证结果 for (Car item : carList) { if (item instanceof Truck) { Truck truck = (Truck) item; System.out.println("卡车最大载重:" + truck.getMaxLoad()); } else { System.out.println("轿车型号:" + item.getModel()); } } } }
方案二:自定义反序列化器(无类型标记时使用)
如果无法修改Web服务返回的JSON格式,没有type字段,可以通过自定义反序列化器,根据子类特有的属性判断类型。
1. 编写自定义反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; public class CarDeserializer extends StdDeserializer<Car> { protected CarDeserializer() { super(Car.class); } @Override public Car deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { JsonNode node = jp.getCodec().readTree(jp); // 根据Truck特有的属性判断类型 if (node.has("maxLoad") && node.has("clearance")) { return jp.getCodec().treeToValue(node, Truck.class); } else { return jp.getCodec().treeToValue(node, Car.class); } } }
2. 注册反序列化器
在父类Car上添加注解,指定使用自定义反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JsonDeserialize(using = CarDeserializer.class) public class Car { // 原有属性和方法省略 }
之后同样可以正常反序列化为List<Car>,Jackson会自动根据属性存在性判断实例类型。
内容的提问来源于stack exchange,提问作者Gary Greenberg
相关产品推荐
相关产品推荐

