Jackson XML反序列化报错:无法从字符串值构造实例
问题背景
尝试用POJO反序列化XML时触发如下错误,无法正确解析列表类型字段:
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of
TestData(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('checka')
at [Source: (com.ctc.wstx.sr.ValidatingStreamReader); line: 3, column: 15] (through reference chain: TC["testData"]->java.util.ArrayList[0])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
待解析的XML内容:
<tc> <testData> <post>checka</post> <xtenantid>netwebshopa</xtenantid> <jsonbody>Testa</jsonbody> </testData> <testData> <post>check</post> <xtenantid>netwebshop</xtenantid> <jsonbody>Test</jsonbody> </testData> </tc>
对应的POJO代码:
TC类
@JacksonXmlRootElement(localName = "tc") public class TC { private List<TestData> testData; public List<TestData> getTestData() { return testData; } public void setTestData(List<TestData> testData) { this.testData = testData; } }
TestData类
public class TestData { private String post; private String xtenantid; private String jsonbody; public String getPost() { return post; } public void setPost(String post) { this.post = post; } public String getXtenantid() { return xtenantid; } public void setXtenantid(String xtenantid) { this.xtenantid = xtenantid; } public String getJsonbody() { return jsonbody; } public void setJsonbody(String jsonbody) { this.jsonbody = jsonbody; } }
问题原因
Jackson XML默认会为列表类型字段寻找外层包裹节点(比如期望用<testDatas>包裹所有<testData>节点),但当前XML结构中直接是多个<testData>作为<tc>的子节点,没有外层包裹。这导致Jackson误将<testData>下的第一个子节点<post>的内容当成了列表项的字符串值,进而尝试用字符串构造TestData对象,触发报错。
解决步骤
修改TC类的testData字段,添加两个注解明确解析规则:
@JacksonXmlElementWrapper(useWrapping = false):禁用列表的外层包裹节点解析,直接将所有同名的<testData>节点作为列表元素。@JacksonXmlProperty(localName = "testData"):显式绑定XML节点名称与Java字段,避免命名规则差异导致的映射错误。
修改后的TC类代码:
@JacksonXmlRootElement(localName = "tc") public class TC { @JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "testData") private List<TestData> testData; public List<TestData> getTestData() { return testData; } public void setTestData(List<TestData> testData) { this.testData = testData; } }
额外注意:确保项目中jackson-dataformat-xml依赖版本与jackson-databind保持一致,避免版本冲突引发其他异常。
内容的提问来源于stack exchange,提问作者Madhav Gutte

