Do I have to do something different in KTor 2.x to...
# ktor
m
Do I have to do something different in KTor 2.x to receive nested JSon classes? I haven't been able to find anything obvious in the KTor serialisation docs. I have a receivable class that arrives perfectly well in one call as an array of this class, but when (in another call) it's a property of a larger class no data (for it) is de-serialised. Although I'm certain the data is sent from the server, it doesn't show up in the log of the received data, which also seems strange. I know this sounds like a foolish question but it used to work, although I'm not sure if this failure is due to the KTor 2.x update or something else.
a
Could you please share your code and an example of JSON?
m
Ok, this is the minimum, is it enough? The method is
Copy code
suspend fun getJsonFromApi(lang: String, purchases: ArrayList<PurchaseData>): TestListResponseSchema {
    return <http://ServerLink.client.post|ServerLink.client.post>("tests") { <etc> }
And that structure is
Copy code
@ExperimentalMultiplatform
@Serializable
class TestListResponseSchema internal constructor() {
    val success: Boolean = false
    val message: String? = null
    val messages: String? = null
    val data: List<TestInventoryInfo> = listOf()
}
And the relevant property there is the "data", the relevant structure is
Copy code
@Serializable
@Parcelize
@ExperimentalMultiplatform
class TestInventoryInfo(                        var subdata: TestSubInfo? = null,
                        @SerialName("width")
                        var aWidth: Int = 0,
                        <various other Ints & Strings>): Parcelable { ... }
The failure is this TestSubInfo. Its definition is
@ExperimentalMultiplatform
@Parcelize
@Serializable
data class TestSubInfo(var id: Int = -1,
                       var sku: String = "",
                       var renewtime: Long = 0,
                       var purchasestatus: Int = 0,
                       var start: Long = 0L,
                       var end: Long? = null): Parcelable { ... }
As I said, an arrayList of TestSubInfo also arrives in another API call, it works just fine.
In case it makes a difference, all this code is in commonMain.
a
Could you please give an example of JSON that is replied by the server?
m
Ok. This is the object that should have a value in subdata. It is one in a list of objects (the others, rightly, have null fo subdata). {"id":23,"fileupdated":"2022-05-21 104953","name":"Preliminary 6 (2020)","authority":"Association of Irish Riding Clubs (AIRC)","thefile":"preliminary-6-2020_en-GB.xml","language":"en-GB","arena":"20x40","width":20,"length":40,"subdata":null,"ordering":1,"lorder":1}
Checking (with curl type tool) shows that what was sent was
Copy code
{
  "id": 23,
  "fileupdated": "2022-05-21 10:49:53",
  "name": "Preliminary 6  (2020)",
  "authority": "Association of Irish Riding Clubs (AIRC)",
  "thefile": "preliminary-6-2020_en-GB.xml",
  "language": "en-GB",
  "arena": "20x40",
  "width": 20,
  "length": 40,
  "subdata": {
    "id": 23,
    "sku": "mm_one_test",
    "renewtime": 1669369742,
    "purchasestatus": 4,
    "start": 1669369339,
    "end": null
  },
  "ordering": 1,
  "lorder": 1
}
I imagine that I've done something embarrassingly stupid, but I haven't been able to find anything.
a
As I can see, the field in JSON is called
subdata
, but in the definition of
TestListResponseSchema
it’s
data
. Is it intended?
m
subdata is a property of TestInventoryInfo. The list of these TestInventoryInfo objects is wrapped in the data property of TestListResponseSchema
(That was second in the structures in response to your first request for code)
a
The following code works for me:
Copy code
fun main(): Unit = runBlocking {
    val client = HttpClient(CIO) {
        install(ContentNegotiation) {
            json(Json {
                ignoreUnknownKeys = true
            })
        }
    }

    val info = client.get("<http://localhost:3333/>").body<TestInventoryInfo>()
    println(info.subdata?.id) // prints 23
}

@Serializable
class TestInventoryInfo(
    var subdata: TestSubInfo? = null,
    @SerialName("width")
    var aWidth: Int = 0,
)

@Serializable
data class TestSubInfo(
    var id: Int = -1,
    var sku: String = "",
    var renewtime: Long = 0,
    var purchasestatus: Int = 0,
    var start: Long = 0L,
    var end: Long? = null
)
For what target do you have a problem with deserialization?
m
Android
a
Please check that the server responds with a correct JSON
If it’s correct then please try to minimize the code sample for reproduction and file an issue.
m
Ah, that's interesting. I had "isLenient" set in my client creation. Removing it shows there's an error somehow! Just looking for that now (thanks)(so far 😄)
Might the treatment of that be a difference between KTor 1 and 2?
a
What error occurs?
m
It says failed with exception: io.ktor.serialization.JsonConvertException: Illegal input
a
In Ktor 1.*
isLenient
is
false
by default. In Ktor 2.* it’s
true
.
m
I had set it explicitly to true. I've just removed that...
Looking at the code it seems to me that isLenient defaults to true in the server but not the client
Ok, resolved. I shouldn't have been so certain about what was sent. There was a difference between the code and my test. Noticing that led to the solution (fix the request).
145 Views