Jackson XML 反序列化问题

Posted

技术标签:

【中文标题】Jackson XML 反序列化问题【英文标题】:Jackson XML Deserialisation Issue 【发布时间】:2018-10-26 17:22:47 【问题描述】:

我能够编写 XML 文档,但是无法反序列化创建的 XML。原始代码在 Kotlin 中,但我发布了 Java 等效代码。

@JacksonXmlRootElement(localName = "assets")
public class Assets 
    @JacksonXmlElementWrapper(useWrapping = false)
    private Asset[] asset;

    public Assets(Asset[] asset) 
        this.asset = asset;
    

    public Asset[] getAsset() 
        return asset;
    

    public void setAsset(Asset[] asset) 
        this.asset = asset;
    


public class Asset 
    @JacksonXmlProperty(isAttribute = true)
    private String type;
    @JacksonXmlProperty(isAttribute = true)
    private String name;
    @JacksonXmlProperty(isAttribute = true)
    private String displayName;
    @JacksonXmlElementWrapper(localName = "permissions")
    private Permission[] permission;

    public Asset(String type, String name, String displayName, Permission[] permission) 
        this.type = type;
        this.name = name;
        this.displayName = displayName;
        this.permission = permission;
    

    public String getType() 
        return type;
    

    public void setType(String type) 
        this.type = type;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getDisplayName() 
        return displayName;
    

    public void setDisplayName(String displayName) 
        this.displayName = displayName;
    

    public Permission[] getPermission() 
        return permission;
    

    public void setPermission(Permission[] permission) 
        this.permission = permission;
    


public class Permission 
    @JacksonXmlProperty(isAttribute = true)
    private String name;
    private Group[] group;

    public Permission(String name, Group[] group) 
        this.name = name;
        this.group = group;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public Group[] getGroup() 
        return group;
    

    public void setGroup(Group[] group) 
        this.group = group;
    

用 (Kotlin) 实例化:

fun writeToXml(obj: Any) : String 
    val xmlMapper = XmlMapper()
    xmlMapper.enable(SerializationFeature.INDENT_OUTPUT)
    return xmlMapper.writeValueAsString(obj)


val assets = Assets(arrayOf(
            Asset("bdo", "approval-matrix", "Approval Matrix", arrayOf(Permission("Create", arrayOf(Group(arrayOf("Admin", "Approver")))))),
            Asset("bdo", "approval-matrix-2", "Approval Matrix 2", arrayOf(Permission("Delete", arrayOf(Group(arrayOf("Admin", "Approver")), Group(arrayOf("Admin-2", "Approver-2"))))))))

val xmlModule = JacksonXmlModule()
val objectMapper = XmlMapper(xmlModule)
println(writeToXml(assets))

生成的 XML 符合预期:

<assets>
  <asset type="bdo" name="approval-matrix" displayName="Approval Matrix">
    <permissions>
      <permission name="Create">
        <groups>
          <group>Admin</group>
          <group>Approver</group>
        </groups>
      </permission>
    </permissions>
  </asset>
  <asset type="bdo" name="approval-matrix-2" displayName="Approval Matrix 2">
    <permissions>
      <permission name="Delete">
        <groups>
          <group>Admin</group>
          <group>Approver</group>
        </groups>
        <groups>
          <group>Admin-2</group>
          <group>Approver-2</group>
        </groups>
      </permission>
    </permissions>
  </asset>
</assets>

但是在尝试反序列化时:

val generated = objectMapper.readValue<Assets>(xmlAssets)

我收到以下错误:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `uk.co.processflows.configuration.entities.Assets` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (StringReader); line: 2, column: 3]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1451)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1027)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1290)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:113)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3011)
    at uk.co.processflows.module.EntryPoint.main(EntryPoint.kt:58)

任何帮助将不胜感激。

【问题讨论】:

您是否尝试过按照错误提示添加默认构造函数? public Asset() 是的,同样的问题。 Assets 也一样?抱歉 - 我刚刚注意到错误是在谈论 Assets 类。 是的,我已经为每种类型添加了一个默认构造函数。 谢谢,每种类型的默认设置都已解决问题。 【参考方案1】:

只是为了澄清答案:

我包括

dependencies 
    ...
    compile(kotlin("reflect"))
    compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+")
    compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.+")
    ...

build.gradle.kts

然后有同样的问题。通过向构造函数添加默认值来更改我的数据类似乎可以解决它。即:

data class HelloWorld(val hello: Boolean, val world: Boolean)

变成

data class HelloWorld(val hello: Boolean = false, val world: Boolean = false)

然后:

const val xml = """
<HelloWorld>
    <hello>true</hello>
    <world>true</world>
</HelloWorld>
"""

将通过数据类在 kotlin 中正常序列化和反序列化。谢谢!

【讨论】:

【参考方案2】:

现在有一个 Jackson 模块,允许它反序列化为 Kotlin 数据类无需添加默认构造函数。

见https://github.com/FasterXML/jackson-module-kotlin

compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+"

尝试将其添加到您的 Kotlin 项目中,这样您就可以保持您的域类“纯”。

【讨论】:

以上是关于Jackson XML 反序列化问题的主要内容,如果未能解决你的问题,请参考以下文章

Jackson XML - 使用命名空间前缀反序列化 XML

jackson xml反序列化内联数组

使用 Jackson 从 XML 到 POJO 的反序列化问题:没有从字符串值反序列化的字符串参数构造函数/工厂方法

Jackson xml反序列化不连续的内联数组

Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素

jackson xml 列出了被识别为重复键的反序列化