I'm trying to parse XML response from API and have a problem with list of "Field" elements. I'm trying to create Field object with attributes and text inside the element like properties of this object and can't find out what annotation I need to use for text of element. I tried to use
@get:Text
@set:Text
and
@field:Text
but got the same error
java.lang.RuntimeException: org.simpleframework.xml.core.PersistenceException: Constructor not matched for class NetworkTestContainer$Field
Can anyone advise me an appropriate annotation for this case, please?
There is XML structure:
<response>
<commands>
<command>
<nick>QUEUECAUSES_LIST</nick>
<result>
<DATASET Version="1.0" Class="TQueryAdv" Name="">
<Row Index="1">
<Field Name="SHOPID" Type="6" Size="0">-1</Field>
<Field Name="IDCODE" Type="6" Size="0">3000000000001</Field>
<Field Name="CAPTION" Type="1" Size="255">Консультация</Field>
<Field Name="PRIORITY" Type="6" Size="0">0</Field>
</Row>
<Row Index="2">
<Field Name="SHOPID" Type="6" Size="0">-1</Field>
<Field Name="IDCODE" Type="6" Size="0">3000000000021</Field>
<Field Name="CAPTION" Type="1" Size="255">Очередь</Field>
<Field Name="PRIORITY" Type="6" Size="0">1</Field>
</Row>
</DATASET>
</result>
</command>
</commands>
</response>
Here are Models
@Root(name = "response", strict = false)
data class NetworkTestContainer(
@field:ElementList(name = "commands")
val commands : List<Command>
) {
@Root(name = "command", strict = false)
data class Command(
@field:Element
val nick : String,
@field:Element(name = "result")
val result : Result
)
@Root(name = "result", strict = false)
data class Result(
@field:Element(name = "DATASET")
val dataSet: DataSet
)
@Root(name = "DATASET", strict = false)
data class DataSet(
@field:Attribute(name = "Version")
val version : String,
@field:Attribute(name = "Class")
val className : String,
@field:Attribute(name = "Name")
val Name : String,
@field:ElementList(inline = true)
val rows : List<Row>
)
@Root(name = "Row", strict = false)
data class Row(
@field:Attribute(name = "Index")
val index : Int,
@field:ElementList(inline = true, entry = "Field")
val fields: List<Field>
// @field:ElementMap(attribute = true, entry = "Field", key = "Name", inline = true)
// val fields : Map<String, String>
)
@Root(name = "Field", strict = false)
data class Field (
@field:Attribute(name = "Name", required = false)
val key : String,
@field:Attribute(name = "Type", required = false)
val type : Int,
@field:Attribute(name = "Size", required = false)
val size : Int,
@get:Text
@set:Text
var text : String
)
}
I'm not familiar with this library, but I tried debugging it and here are my findings.
According to the documentation, this library works by either using an empty constructor with field/getter/setter annotation or by using constructor injection + getter annotation.
In the first case you would need to get rid of your
datamodifier and use@field:annotation, pluslateinit varor other approaches to initialise all fields when creating the object. Example:This prints:
As you can see, this is not ideal but it works.
A - probably - better approach would involve using constructor injection, which also requires annotated getters or fields (as specified in the documentation linked above).
In order to do that you need to use
@param:annotations (as you need to annotate constructor arguments) plus@get:annotations (as you need to annotate the getter). Example:This prints the same thing as above (apart from some styling differences for strings):