我们如何将kotlin.serialize与Ktor的HttpClient一起使用,以列表作为根来反序列化/序列化JSON? 我正在创建HttpClient,如下所示:
HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer().apply {
setMapper(MyClass::class, MyClass.serializer())
setMapper(AnotherClass::class, AnotherClass.serializer())
}
}
install(ExpectSuccess)
}
看来我需要为列表设置映射器,但是泛型是不可能的。 我看到我可以使用MyClass.serializer((.list获取它的序列化程序,但是注册它以在http请求上反序列化/序列化并不简单。 有人知道一个好的解决方案吗?
您可以编写包装器和自定义序列化程序:
@Serializable
class MyClassList(
val items: List<MyClass>
) {
@Serializer(MyClassList::class)
companion object : KSerializer<MyClassList> {
override val descriptor = StringDescriptor.withName("MyClassList")
override fun serialize(output: Encoder, obj: MyClassList) {
MyClass.serializer().list.serialize(output, obj.items)
}
override fun deserialize(input: Decoder): MyClassList {
return MyClassList(MyClass.serializer().list.deserialize(input))
}
}
}
注册它:
HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer().apply {
setMapper(MyClassList::class, MyClassList.serializer())
}
}
}
并使用:
suspend fun fetchItems(): List<MyClass> {
return client.get<MyClassList>(URL).items
}
更新 ktor 1.3.0:
现在,您可以直接从客户端接收默认集合(例如列表(:
@Serializable
data class User(val id: Int)
val response: List<User> = client.get(...)
// or client.get<List<User>>(...)
在 ktor 1.3.0 之前:
目前还没有办法在 kotlinx.serialization 中(反(序列化这样的 JSON。
对于序列化,您可以尝试如下操作:
fun serializer(data: Any) = if (data is List<*>) {
if (data is EmptyList) String::class.serializer().list // any class with serializer
else data.first()::class.serializer().list
} else data.serializer()
并且没有已知的方法来获取列表反序列化程序。
这更像是一种解决方法,但在逐步完成KotlinxSerializer
代码后,我看不到任何其他方法。 例如,如果您查看KotlinxSerializer.read()
,您会发现它尝试根据type
查找mapper
,但在这种情况下,它只是一个kotlin.collections.List
并且无法解决。 我试过调用类似setListMapper(MyClass::class, MyClass.serializer())
的东西,但这仅适用于序列化(通过write
中的lookupSerializerByData
方法使用(
override suspend fun read(type: TypeInfo, response: HttpResponse): Any {
val mapper = lookupSerializerByType(type.type)
val text = response.readText()
@Suppress("UNCHECKED_CAST")
return json.parse(mapper as KSerializer<Any>, text)
}
所以,我最终做的是这样的(注意serializer().list
电话(
suspend fun fetchBusStops(): List<BusStop> {
val jsonArrayString = client.get<String> {
url("$baseUrl/stops.json")
}
return JSON.nonstrict.parse(BusStop.serializer().list, jsonArrayString)
}
不理想,显然没有利用JsonFeature
。
我碰巧在 Kotlin/JS 上遇到了同样的问题,并设法以这种方式修复它:
private val client = HttpClient(Js) {
install(JsonFeature) {
serializer = KotlinxSerializer().apply {
register(User.serializer().list)
}
}
}
...
private suspend fun fetchUsers(): Sequence<User> =
client.get<List<User>> {
url("$baseUrl/users")
}.asSequence()
希望这对:)有所帮助