Search code examples
androidkotlinretrofit2simple-framework

Serializing retrofit xml response with SimpleXML in kotlin


I'm attempting to serialize a retrofit xml response into an object using SimpleXML.

However the following exception occurs:

org.simpleframework.xml.core.ValueRequiredException: Unable to satisfy @org.simpleframework.xml.ElementList(data=false, empty=true, entry=, inline=true, name=ALLFile, required=true, type=void) on field 'files''

Example of response:

<LIST> 
   <ALLFile>
      <File>
         <NAME>SOME FILE NAME</NAME>
         <FPATH>SOME FILE PATH</FPATH>
         <SIZE>160053622</SIZE>
         <TIMECODE>1299673239</TIMECODE>
         <TIME>2018/11/23 14:04:46</TIME>
         <ATTR>33</ATTR>
      </File>
   </ALLFile>
   <ALLFile> 
      <File> 
	 <NAME>SOME FILE NAME</NAME>
         <FPATH>SOME FILE PATH</FPATH>
         <SIZE>160053622</SIZE>
         <TIMECODE>1299673559</TIMECODE>
         <TIME>2018/11/23 14:14:46</TIME>
         <ATTR>33</ATTR>
      </File>
   </ALLFile>
</LIST>

Objects:

@Root(name = "LIST", strict = false)
data class ListResponse @JvmOverloads constructor(
    @field:ElementList(name = "ALLFile", inline = true) var files: List<GetVideosResponse>? = null
)

@Root(strict = false, name = "File")
data class GetVideosResponse @JvmOverloads constructor(
    @field:Element(name = "NAME", required = false) var name: String? = null,
    @field:Element(name = "FPATH", required = false) var fPath: String? = null,
    @field:Element(name = "SIZE", required = false) var size: Int? = null,
    @field:Element(name = "TIMECODE", required = false) var timeCode: Long? = null,
    @field:Element(name = "TIME", required = false) var time: String? = null,
    @field:Element(name = "ATTR", required = false) var attr: Int? = null)

I'm receiving a 200 response from the server, so can rule out my request logic as the problem. Which leads me to believe the issue lies with serializing the objects, any ideas?


Solution

  • Found a way round this, not necessarily the answer but it works for me...

    I took the XML response as a string, converted it to JSON then used my usual JSON serializing library (moshi) to serialize the JSON into an object.

    private fun parseXmlToJsonObject(xml: String) : String {
        var jsonObj: JSONObject? = null
        try {
            jsonObj = XML.toJSONObject(xml)
        } catch (e: JSONException) {
            Log.e("JSON exception", e.message)
            e.printStackTrace()
        }
    
        return jsonObj.toString()
    }
    
    fun<T> parseResponse(xml: String, clazz: Class<T>) : T {
        try {
            return initializeMoshi().adapter(clazz).fromJson(parseXmlToJsonObject(xml))!!
        }catch (e: IOException){
            throw IllegalArgumentException("Could not deserialize: $xml into class: $clazz")
        }
    }
    
    private fun initializeMoshi(): Moshi {
        return Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .build()
    }
    

    And called it like so:

    val myObject = parseResponse(response.body()!!.string(), MyJsonClass::class.java)