简体   繁体   中英

POJO object for this XML response in kotlin

I'm working with an API which returns XML something like this:

<xyz-objects version="1.0">
    <object pk="1" model="roll">
        <field type="BigIntegerField" name="roll_number">1000000714</field>
        <field type="CharField" name="status">DL</field>
        <field name="scans">
            <object pk="1" model="scan_stages">
                <field type="DateTimeField" name="updated_on">11 Jul, 2017, 17:40</field>
            </object>
        </field>        
    </object>
</xyz-objects>

I'm using Jackson's XML mapper.

I tried writing a POJO object for this but that doesn't work.

How do I handle attributes of elements like type and name? Can you exemplify?

As you didn't provide the schema, it's hard to guess some parts of your model. Especially, it's hard to guess field model. So I will deserialize it into a JsonNode , dynamic object that can handle literally everything. JsonIgnoreProperties just in case you have some extra fields, not mentioned here.

First, create some data classes:

@XmlRootElement(name = "xyz-objects")
@JsonIgnoreProperties(ignoreUnknown = true)
data class XyzObjects(
        @JacksonXmlProperty(isAttribute = true)
        val version: String,

        @JsonProperty(value = "object")
        @JacksonXmlElementWrapper(useWrapping = false)
        val objects: List<Object>
)

@XmlRootElement(name = "object")
@JsonIgnoreProperties(ignoreUnknown = true)
data class Object(
        @JacksonXmlProperty(isAttribute = true)
        val pk: String,

        @JacksonXmlProperty(isAttribute = true)
        val model: String,

        @JsonProperty(value = "field")
        @JacksonXmlElementWrapper(useWrapping = false)
        val fields: List<JsonNode>
)

Answering your question: you can handle attrributes with by using isAttribute attribute of JacksonXmlProperty . Lists can be handled with JacksonXmlElementWrapper + JsonProperty (don't be fooled by name, it is used to handle plurals in names, thus making them more human readable in XML too).

In order to be able to work with data classes, you'll need to register Kotlin module with registerKotlinModule :

val text = """<xyz-objects version="1.0">
<object pk="1" model="roll">
    <field type="BigIntegerField" name="roll_number">1000000714</field>
    <field type="CharField" name="status">DL</field>
    <field name="scans">
        <object pk="1" model="scan_stages">
            <field type="DateTimeField" name="updated_on">11 Jul, 2017, 17:40</field>
        </object>
    </field>
</object>
</xyz-objects>"""
val mapper = XmlMapper().registerKotlinModule()
val node = mapper.readValue<XyzObjects>(text)

println(node)

It will print:

XyzObjects(version=1.0, objects=[Object(pk=1, model=roll, fields=[{"type":"BigIntegerField","name":"roll_number","":"1000000714"}, {"type":"CharField","name":"status","":"DL"}, {"name":"scans","object":{"pk":"1","model":"scan_stages","field":{"type":"DateTimeField","name":"updated_on","":"11 Jul, 2017, 17:40"}}}])])

Based on the investigation I did in https://github.com/FasterXML/jackson-module-kotlin/issues/138 here's a workaround that's a bit more typed that the JsonNode workaround by madhead

data class Field(
    @JacksonXmlProperty(isAttribute = true)
    val type: String,

    @JacksonXmlProperty(isAttribute = true)
    val name: String,
) {
    @JacksonXmlText
    lateinit var value: String private set
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM