Jackson多态模型序列化反序列化异常,求POJO配置修正方案
需要构建可完成序列化与反序列化的对象模型,对接第三方服务的请求与响应,目标JSON格式如下:
目标JSON示例
{ "name": "Johnny", "vehicles": [{ "vehicleType": "car", "vehicleInfo": { "maxSeatCount": 2, "coupe": true } }, { "vehicleType": "truck", "vehicleInfo": { "towingCapacity": "3000lb", "bedLength": "6ft" } }] }
原POJO实现
PersonInfo.java
public class PersonInfo { private String name; private List<Vehicle> vehicles; // 省略getter/setter方法 }
Vehicle.java
public class Vehicle { private String vehicleType; private VehicleInfo vehicleInfo; // 省略getter/setter方法 }
VehicleInfo.java
@JsonTypeInfo(use = Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "vehicleType") @JsonSubTypes({ @Type(value = CarInfo.class, name="car"), @Type(value = TruckInfo.class, name="truck") }) public abstract class VehicleInfo {}
CarInfo.java
public class CarInfo extends VehicleInfo{ private int maxSeatCount; private boolean coupe; // 省略getter/setter方法 }
TruckInfo.java
public class TruckInfo extends VehicleInfo{ private String towingCapacity; private String bedLength; // 省略getter/setter方法 }
遇到的问题
- 序列化时,
vehicleInfo对象内额外生成了vehicleType属性,不符合目标格式:
{ "name" : "Johnny", "vehicles" : [ { "vehicleType" : "car", "vehicleInfo" : { "vehicleType" : "car", // 此处不应存在 "maxSeatCount" : 2, "coupe" : false } }, { "vehicleType" : "truck", "vehicleInfo" : { "vehicleType" : "truck", // 此处不应存在 "towingCapacity" : "3000lb", "bedLength" : "6ft" } } ] }
- 反序列化时抛出异常,提示无法解析
VehicleInfo子类型:
Exception in thread "main"
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not
resolve subtype of [simple type, class
com.kodakandla.file.VehicleInfo]: missing type id property
'vehicleType' (for POJO property 'vehicleInfo') at [Source:
(String)"{"name":"Johnny","vehicles":[{"vehicleType":"car","vehicleInfo":{"maxSeatCount":2,"coupe":true}},{"vehicleType":"truck","vehicleInfo":{"towingCapacity":"3000lb","bedLength":"6ft"}}]}";
line: 1, column: 95] (through reference chain:
com.kodakandla.file.PersonInfo["vehicles"]->java.util.ArrayList[0]->com.kodakandla.file.Vehicle["vehicleInfo"])
at
com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
at
com.fasterxml.jackson.databind.DeserializationContext.missingTypeIdException(DeserializationContext.java:2083)
at
com.fasterxml.jackson.databind.DeserializationContext.handleMissingTypeId(DeserializationContext.java:1596)
问题根源在于@JsonTypeInfo的配置位置错误,需要将类型信息的处理逻辑移到Vehicle类上,而非VehicleInfo类。具体修改如下:
1. 调整VehicleInfo类,移除类型注解
删除VehicleInfo上的所有Jackson类型注解,因为类型判断的逻辑由其父对象Vehicle负责:
public abstract class VehicleInfo {}
2. 修改Vehicle类,添加类型注解关联VehicleInfo
在Vehicle类的vehicleInfo字段上添加类型注解,指定类型ID来自同层级的vehicleType属性:
public class Vehicle { private String vehicleType; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "vehicleType", visible = true) @JsonSubTypes({ @JsonSubTypes.Type(value = CarInfo.class, name = "car"), @JsonSubTypes.Type(value = TruckInfo.class, name = "truck") }) private VehicleInfo vehicleInfo; // 省略getter/setter方法 }
关键参数说明
include = JsonTypeInfo.As.EXTERNAL_PROPERTY:指定类型标识来自当前对象的外部属性(即同层级的vehicleType)visible = true:确保vehicleType字段在反序列化时不会被Jackson当作类型标识丢弃,能正常读取和使用
3. 验证效果
修改完成后:
- 序列化生成的JSON将与目标格式完全一致,
vehicleInfo内部不会再额外生成vehicleType属性 - 反序列化时Jackson能正确识别
CarInfo和TruckInfo类型,不会再抛出类型解析异常
内容的提问来源于stack exchange,提问作者RKodakandla

