当前位置: 首页 > news >正文

Jackson序列化框架中处理泛型DTO转换

Jackson序列化框架中处理泛型DTO转换

作用是解决Java编译后泛型信息被擦除,导致最后解析时强转报异常

JavaType javaType = objectMapper.getTypeFactory().constructParametricType(MdmInvokeParamDTO.class, MdmMaterialDTO.class);
MdmInvokeParamDTO<MdmMaterialDTO> mdmInvokeParam = objectMapper.convertValue(inputParam, javaType);

代码解释:

JavaType javaType = objectMapper.getTypeFactory().constructParametricType(MdmInvokeParamDTO.class, MdmMaterialDTO.class);

objectMapper:Jackson的核心对象,负责序列化/反序列化(对象<->JSON/Map)
objectMapper.getTypeFactory():获取Jackson的“类型工厂”,专门用来创建复杂类型(泛型、集合、数组等)的类型描述对象
constructParametricType:创建“带泛型的类型描述对象”

使用代码示例说明:

// 泛型参数DTO:代表品号数据
public class MdmMaterialDTO {private String partNo; // 代表品号// 省略get/set
}// 泛型容器DTO:MDM推送的统一参数格式
public class MdmInvokeParamDTO<T> {private List<T> value; // 核心字段:存放具体业务数据(如代表品号列表)// 省略get/set
}

模拟接口传入的原始参数(inputParam)

// 模拟接口传入的inputParam(实际可能是Map/JSONObject)
Map<String, Object> inputParam = new HashMap<>();
List<Map<String, String>> valueList = new ArrayList<>();
Map<String, String> materialMap = new HashMap<>();
materialMap.put("partNo", "P123456"); // 代表品号数据
valueList.add(materialMap);
inputParam.put("value", valueList);

当直接用MdmInvokeParamDTO.class转换:

ObjectMapper objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);// 错误写法:没有指定泛型T的实际类型
MdmInvokeParamDTO<MdmMaterialDTO> mdmInvokeParam = objectMapper.convertValue(inputParam, MdmInvokeParamDTO.class);// 尝试获取value并强转MdmMaterialDTO → 必报异常
List<MdmMaterialDTO> materialList = mdmInvokeParam.getValue();
MdmMaterialDTO firstItem = materialList.get(0); // 这里会抛出ClassCastException!

抛出的异常:java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.xxx.MdmMaterialDTO
核心原因:Jackson 把value里的每个元素解析成了LinkedHashMap(而非MdmMaterialDTO),强转时直接报错。

为什么解析后会变成List
Java泛型擦除+Jackson的默认解析规则造成

  1. Java编译后泛型信息会被彻底擦除:MdmInvokeParamDTO<MdmMaterialDTO>编译后字节码里只有MdmInvokeParamDTOMdmInvokeParamDTO类中的List<T> value编译后会变成List value(T被擦除后变成Object),因此MdmInvokeParamDTO.class这个Class对象里,完全没有T是MdmMaterialDTO的信息
  2. Jackson的默认解析规则:Jackson拿到MdmInvokeParamDTO.class时,只能知道该类中有一个List类型的value字段,不知道该List中的对象类型是什么,因此Jackson会按“最安全的默认规则”解析:
  3. 把JSON/Map中的数组/列表结构解析成List
  4. 把列表中的每个元素(JSON/Map),默认解析成LinkedHashMap(JSON的本质是键值对,Jackson用LinkedHashMap存储)
  5. mdmInvokeParam.getValue()的实际类型是List<LinkedHashMap>,而非List<MdmMaterialDTO>

T是Object和MdmMaterialDTO的区别是什么?
区别在于能不能直接用
T=Object:只能知道里面是对象,不知道具体的字段,不能直接使用
T=MdmMaterialDTO:能够知道里面装的是代表品号 DTO,有partNo字段,可以使用getPartNo()