Search code examples
javaxmlkotlinjacksonretrofit2

How to parse XML with two elements with the same name?


I need to parse this XML returned by Retrofit:

<data>
    <id>1</id>
    <subdata>
        <id>1a</id>
    </subdata>
    <subdata>
        <id>1b</id>
    </subdata>
</data>

I'm using Jackson:

Retrofit.Builder()
    .baseUrl("https://www.web.com/")
    .addConverterFactory(JacksonConverterFactory.create(XmlMapper()
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
        .registerKotlinModule()))
    .build().create(DataApiService::class.java)

I tried with these data classes for the object:

data class Data(
    val id: String,
    @JacksonXmlProperty(localName = "subdata")
    val subdata1: SubData,
    @JacksonXmlProperty(localName = "subdata")
    val subdata2: SubData
)

data class SubData(
    val id: String,
)

But it doesn't work:

IllegalArgumentException: Conflicting getter definitions for property "subdata": com.data.model.Data#getSubdata1() vs com.data.model.Data#getSubdata2()

Solution

  • You can use the Annotation @JacksonXmlElementWrapper(useWrapping = false) to tell Jackson that you have multiple elements with the same name and de/serialize it as a List<Subdata>:

    data class Data(
        val id: String,
        @JacksonXmlElementWrapper(useWrapping = false)
        @JacksonXmlProperty(localName = "subdata")
        val subdata: List<SubData>
    )
    
    data class SubData(
        val id: String,
    )
    

    useWrapping = false tells Jackson that your XML elements are directly underneath the root and not underneath a separate Wrapper.