Java Jackson XML泛型反序列化异常问题排查
问题原因:Java泛型类型擦除
你遇到的问题核心是Java泛型的类型擦除机制:
- 编译后,
MyXmlManager<T>中的泛型参数T会被擦除为Object,所以你在方法中创建的new TypeReference<XmlGeneric<T>>() {},在运行时实际代表的是XmlGeneric<Object>类型。 - Jackson无法获取到
T的实际类型(比如Person),只能将XML节点默认反序列化为LinkedHashMap来存储键值对,这就是为什么你看到{name=charles, userid=1}这种输出,强制转换时会抛出ClassCastException。
而直接使用new TypeReference<XmlGeneric<Person>>() {}时,编译器会把Person这个具体类型保留在匿名内部类的类型元数据中(TypeReference正是利用匿名内部类能保留泛型类型信息的特性工作),所以Jackson能正确识别目标类型,完成反序列化。
解决方案
下面提供两种可行的修复方式,核心都是在运行时为Jackson提供明确的泛型类型信息:
方法1:在反序列化方法中传入目标类型信息
修改MyXmlManager,让方法接收Class<T>或者TypeReference,直接传递给Jackson:
方式1.1 传入Class<T>构造JavaType
public class MyXmlManager { final static XmlMapper oXmlMapper = new XmlMapper(); public <T> XmlGeneric<T> xmlDeserialization(String sXmlData, Class<T> elementType) throws JsonProcessingException { // 构造XmlGeneric<T>的JavaType JavaType targetType = oXmlMapper.getTypeFactory() .constructParametricType(XmlGeneric.class, elementType); return oXmlMapper.readValue(sXmlData, targetType); } }
调用代码:
MyXmlManager myXmlManager = new MyXmlManager(); XmlGeneric<Person> xmlPerson = myXmlManager.xmlDeserialization(xmlPersonData, Person.class); System.out.println(xmlPerson); // 输出:XmlGeneric [rows=[person [name=charles, userid=1], person [name=arthur, userid=2]]]
方式1.2 直接传入TypeReference
public class MyXmlManager { final static XmlMapper oXmlMapper = new XmlMapper(); public <T> XmlGeneric<T> xmlDeserialization(String sXmlData, TypeReference<XmlGeneric<T>> typeRef) throws JsonProcessingException { return oXmlMapper.readValue(sXmlData, typeRef); } }
调用代码:
MyXmlManager myXmlManager = new MyXmlManager(); XmlGeneric<Person> xmlPerson = myXmlManager.xmlDeserialization(xmlPersonData, new TypeReference<XmlGeneric<Person>>() {});
方法2:在MyXmlManager实例化时保存类型信息
如果希望MyXmlManager实例绑定固定的泛型类型,可以在构造时传入类型信息并保存:
public class MyXmlManager<T> { final static XmlMapper oXmlMapper = new XmlMapper(); private final JavaType targetType; public MyXmlManager(Class<T> elementType) { this.targetType = oXmlMapper.getTypeFactory() .constructParametricType(XmlGeneric.class, elementType); } public XmlGeneric<T> xmlDeserialization(String sXmlData) throws JsonProcessingException { return oXmlMapper.readValue(sXmlData, targetType); } }
调用代码:
MyXmlManager<Person> myXmlManager = new MyXmlManager<>(Person.class); XmlGeneric<Person> xmlPerson = myXmlManager.xmlDeserialization(xmlPersonData);
以上两种方法都能让Jackson在运行时获取到T的实际类型,从而正确将<row>节点反序列化为对应的POJO对象。
内容的提问来源于stack exchange,提问作者Charles
相关产品推荐
相关产品推荐

