tieskedh
12/16/2020, 7:28 PM{
"offset":0,
"limit":15,
"count":1,
//and a field with custom fieldname with the items
"fooItems": [...]
}
Can I transform this somehow in a class like this:
class PaginationResult<T>(
val offset : Int,
val limit : Int,
val count : Int,
val items : List<T>
}
@Serializable FooItem
@serializable BarItem
Javier
12/16/2020, 7:56 PMtieskedh
12/16/2020, 8:13 PM@Serializable(ListResponseSerializer::class)
class ListResponse<T>(
val offset: Int,
val limit: Int,
val count: Int,
val totalCount: Int,
val items : List<T>
)
class ListResponseSerializer<T>(
private val dataSerializer : KSerializer<T>
) : KSerializer<ListResponse<T>>{
override fun deserialize(
decoder: Decoder
): ListResponse<T> {
val jsonInput = decoder as JsonDecoder ?: error("only json supported")
val json = jsonInput.decodeJsonElement().jsonObject
val element = json.keys - arrayOf("offset", "limit", "count", "totalCount")
val elementKey = element.single()
val i = json.keys.indexOf(elementKey)
val listSerializable = ListSerializer(dataSerializer)
return ListResponse(
offset = json["offset"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
limit = json["limit"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
count = json["count"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
totalCount = json["totalCount"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
items = decoder.decodeSerializableElement(listSerializable.descriptor, i, listSerializable)
)
}
override val descriptor = buildClassSerialDescriptor("ListResponse"){
element<Int>("offset")
element<Int>("limit")
element<Int>("count")
element<Int>("totalCount")
element("items", dataSerializer.descriptor)
}
override fun serialize(encoder: Encoder, value: ListResponse<T>) : Nothing=TODO()
}
Javier
12/16/2020, 8:24 PMJavier
12/16/2020, 8:25 PMtieskedh
12/16/2020, 8:35 PMfooItems
and in another call its barItems
.
I wanted to rename those changing field to items
and then link them with a generic type.
During retrieval, I am always aware of the real type, so the generic itself should always work.
The result would be that I have one generic data-class that knows about pagination.
All my other data-classes just know about their own data.
Also, I would keep it generic, which means that the items which I'm retrieving can be completely independent and they don't have to be declared in a serialzarsmodule.tieskedh
12/16/2020, 9:05 PM@Serializable
class ResultA(
val id : Int,
val name : String
)
fun test(){
val result1 = """{
"offset":0,
"limit":15,
"count":15,
"totalCount":"54",
"aList": [
{"id":1,"name":"foo"},
{"id":2,"name":"bar"},
{"id":3,"name":"foobar"}
]
}"""
Json.decodeFromString<ListResponse<ResultA>>(result1)
}
@Serializable
class ResultB(
val id : Int,
val age : Int,
)
@Test
fun test2(){
val result2 = """{
"offset":0,
"limit":15,
"count":15,
"totalCount":"54",
"bList": [
{"id":1,"name":10},
{"id":2,"name":20},
{"id":3,"name":30}
]
}"""
Json.decodeFromString<ListResponse<ResultB>>(result2)
}
@Serializable(ListResponseSerializer::class)
class ListResponse<T>(
val offset: Int,
val limit: Int,
val count: Int,
val totalCount: Int,
val items : List<T>
)
Javier
12/16/2020, 9:11 PMtieskedh
12/16/2020, 9:14 PMtieskedh
12/16/2020, 9:31 PMclass ListResponseSerializer<T>(
private val dataSerializer : KSerializer<T>
) : KSerializer<ListResponse<T>>{
override fun deserialize(decoder: Decoder): ListResponse<T> {
val jsonInput = decoder as? JsonDecoder ?: error("only json supported")
val json = jsonInput.decodeJsonElement().jsonObject
val element = json.keys - arrayOf("offset", "limit", "count", "totalCount")
val elementKey = element.single()
val value = json[elementKey]
return ListResponse(
offset = json["offset"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
limit = json["limit"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
count = json["count"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
totalCount = json["totalCount"]!!.<http://jsonPrimitive.int|jsonPrimitive.int>,
items = Json.decodeFromJsonElement(ListSerializer(dataSerializer), value!!)
)
}
override val descriptor = buildClassSerialDescriptor("ListResponse"){
element<Int>("offset")
element<Int>("limit")
element<Int>("count")
element<Int>("totalCount")
element("items", listSerialDescriptor(dataSerializer.descriptor))
}
override fun serialize(encoder: Encoder, value: ListResponse<T>) : Nothing=TODO()
}
tieskedh
12/16/2020, 9:32 PM