
本文探讨Jackson XML反序列化过程中,针对列表类型数据(如List)出现的MismatchedInputException和no String-argument constructor错误。核心问题在于Jackson默认无法正确识别XML中的列表结构,将其误解为单个字符串值。解决方案是利用@JacksonXmlElementWrapper(useWrapping = false)和@JacksonXmlProperty注解,明确指定XML元素的包装方式和名称映射,确保Jackson能正确解析嵌套的列表数据,从而实现XML到Java对象的顺利转换。
Jackson XML反序列化概述
jackson是一个功能强大的java库,用于处理json和xml数据。通过jackson-dataformat-xml模块,jackson能够方便地将xml字符串或文件反序列化为java对象,或将java对象序列化为xml。然而,在处理复杂的xml结构,特别是包含列表(list)类型数据时,可能会遇到一些挑战,需要借助特定的注解来指导jackson的解析行为。
列表类型数据反序列化常见问题:MismatchedInputException
当尝试将一个包含嵌套列表的XML文件反序列化为Java对象时,如果未正确配置,Jackson可能会抛出com.fasterxml.jackson.databind.exc.MismatchedInputException异常,并伴随“Cannot construct instance of YourBean (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (‘…’)”的错误信息。
示例场景:
假设有以下Java数据传输对象(DTO):
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import com.fasterxml.jackson.annotation.JsonProperty;import lombok.Getter;import lombok.NoArgsConstructor;import lombok.Setter;import java.util.List;@JsonIgnoreProperties(ignoreUnknown = true)@Getter @Setter @NoArgsConstructorpublic class FINSTABean { @JsonProperty("STA_VER") String STA_VER; @JsonProperty("FINSTA03") List FINSTA03BeanList; // 期望解析为列表}@JsonIgnoreProperties(ignoreUnknown = true)@Getter @Setter @NoArgsConstructorpublic class FINSTA03Bean { @JsonProperty("S28_CISLO_VYPISU") String S28_CISLO_VYPISU; String S25_CISLO_UCTU; // 假设此字段在XML中存在,但未显式注解}
以及对应的XML数据片段:
01.0000 10 20
当使用XmlMapper尝试反序列化时:
XmlMapper xmlMapper = new XmlMapper();FINSTABean bean = xmlMapper.readValue(file, FINSTABean.class);
可能会遇到如下错误:
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.lelifin.alfa.parsers.csob_xml.FINSTA03Bean` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('10') at [Source: (File); line: 5, column: 29] (through reference chain: com.lelifin.alfa.parsers.csob_xml.FINSTABean["FINSTA03"]->java.util.ArrayList[0])
这个错误表明Jackson尝试将XML中的元素的内容(例如10)直接反序列化为一个FINSTA03Bean对象,而不是将其识别为一个包含FINSTA03Bean对象的列表。由于FINSTA03Bean没有接受单个字符串参数的构造函数或工厂方法,导致反序列化失败。
问题根源:Jackson对XML列表结构的默认处理
Jackson在处理XML时,对于集合类型的字段,默认行为是期望有一个包装元素(wrapper element)来包含列表中的所有项。例如,如果XML结构是:
... ...
而我们的XML中元素直接作为父元素的子元素重复出现,并没有一个额外的包装元素来明确表示这是一个列表。在这种情况下,Jackson会误将第一个元素视为一个独立的、非列表的字段,并尝试将其内容(例如10)作为一个字符串值来构建FINSTA03Bean,从而引发MismatchedInputException。
解决方案:使用@JacksonXmlElementWrapper和@JacksonXmlProperty
为了正确指导Jackson处理这种扁平化的列表结构,我们需要使用jackson-dataformat-xml提供的特定注解:@JacksonXmlElementWrapper和@JacksonXmlProperty。
@JacksonXmlElementWrapper(useWrapping = false)这个注解用于指示Jackson如何处理集合或数组类型的字段。当useWrapping设置为false时,它告诉Jackson该集合的元素不是由一个额外的包装XML元素所包裹,而是直接作为父元素的子元素出现。这正是我们当前XML结构所需要的。
@JacksonXmlProperty(localName = “…”)@JacksonXmlProperty是Jackson XML模块特有的注解,用于将Java对象的字段映射到XML元素或属性。它类似于@JsonProperty,但专为XML设计,提供了更多XML相关的控制。localName属性用于指定XML元素的名称。
修正后的DTO代码:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;import lombok.Getter;import lombok.NoArgsConstructor;import lombok.Setter;import java.util.List;@JsonIgnoreProperties(ignoreUnknown = true)@Getter @Setter @NoArgsConstructorpublic class FINSTABean { @JacksonXmlProperty(localName = "STA_VER") // 使用JacksonXmlProperty映射XML元素名 String STA_VER; // 关键修正: // 1. @JacksonXmlProperty(localName = "FINSTA03"):将Java字段FINSTA03BeanList映射到XML元素FINSTA03。 // 2. @JacksonXmlElementWrapper(useWrapping = false):指示FINSTA03BeanList的元素不是由一个额外的包装元素包裹, // 而是FINSTA03元素本身就代表列表中的一个项。 @JacksonXmlProperty(localName = "FINSTA03") @JacksonXmlElementWrapper(useWrapping = false) List FINSTA03BeanList;}@JsonIgnoreProperties(ignoreUnknown = true) // 仍然保留,忽略XML中Java对象未定义的字段@Getter @Setter @NoArgsConstructorpublic class FINSTA03Bean { @JacksonXmlProperty(localName = "S28_CISLO_VYPISU") String S28_CISLO_VYPISU; @JacksonXmlProperty(localName = "S25_CISLO_UCTU") // 如果XML中存在此元素,也应明确映射 String S25_CISLO_UCTU;}
通过上述修改,Jackson现在能够正确地识别FINSTA03BeanList字段对应的XML结构。它会知道元素并不是一个单一的字符串值,而是列表中的一个对象实例,并且会逐个解析所有同名的元素,并将它们收集到FINSTA03BeanList中。
注意事项与最佳实践
@JsonProperty vs. @JacksonXmlProperty: 尽管@JsonProperty在某些情况下也能用于XML映射,但@JacksonXmlProperty是Jackson XML模块提供的更专业、更强大的注解,建议在处理XML时优先使用它,尤其是在需要精细控制XML元素或属性映射时。useWrapping = true 的场景: 如果XML结构中确实存在一个包装元素,例如:
... ...
那么在FINSTABean中,FINSTA03BeanList字段应该这样注解:
@JacksonXmlElementWrapper(localName = "FINSTA03List") // 包装元素名称@JacksonXmlProperty(localName = "FINSTA03") // 列表项元素名称List FINSTA03BeanList;
此时,useWrapping默认为true,或者可以显式设置为true。
忽略未知属性: @JsonIgnoreProperties(ignoreUnknown = true) 是一个非常有用的注解,它指示Jackson在反序列化时忽略XML中存在但Java对象中没有对应字段的元素或属性,这可以提高代码的健壮性。Lombok集成: @Getter, @Setter, @NoArgsConstructor等Lombok注解与Jackson完美兼容,它们在编译时生成了必要的getter/setter方法和无参构造函数,满足Jackson反序列化的要求。XML编码: XML文件头部的encoding=”windows-1250″指定了字符编码。在Java中读取文件时,确保使用正确的编码方式,例如new InputStreamReader(new FileInputStream(file), “windows-1250”),以避免乱码问题。
总结
在Jackson XML反序列化过程中,处理列表类型数据是一个常见的陷阱。MismatchedInputException通常是由于Jackson未能正确识别XML中的列表结构导致的。通过巧妙地运用@JacksonXmlElementWrapper和@JacksonXmlProperty这两个Jackson XML模块特有的注解,我们可以精确地指导Jackson如何解析复杂的XML结构,特别是当列表元素没有显式包装器时,使用@JacksonXmlElementWrapper(useWrapping = false)能够有效解决问题。理解并正确应用这些注解,是实现高效、健壮Jackson XML数据处理的关键。
以上就是Jackson XML 反序列化深度指南:处理列表类型数据的常见陷阱与解决方案的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/56808.html
微信扫一扫
支付宝扫一扫