KtorのHttpClientでkotlin.serializeを使用して、リストをルートとしてJSONを逆シリアル化/シリアル化するにはどうすればよいですか?私は次のようにHttpClientを作成しています:
HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer().apply {
setMapper(MyClass::class, MyClass.serializer())
setMapper(AnotherClass::class, AnotherClass.serializer())
}
}
install(ExpectSuccess)
}
ListにMapperを設定する必要があるようですが、ジェネリックでは不可能です。 MyClass.serializer()。listを使用してシリアライザーを取得できるようですが、httpリクエストでデシリアライズ/シリアライズするように登録するのは簡単ではありません。誰かが良い解決策を知っていますか?
Kotlinx.serializationでそのようなJSONを(逆)シリアル化する方法はまだありません。
シリアル化の場合は、次のようなものを試すことができます。
fun serializer(data: Any) = if (data is List<*>) {
if (data is EmptyList) String::class.serializer().list // any class with serializer
data.first()::class.serializer().list
} else data.serializer()
また、リストデシリアライザーを取得する既知の方法はありません。
ラッパーとカスタムシリアライザーを作成できます。
@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
}
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()
お役に立てれば :)
これはより回避策ですが、KotlinxSerializer
コードをステップ実行した後、他の方法を見つけることができませんでした。たとえば、KotlinxSerializer.read()
を見ると、mapper
に基づいてtype
を検索しようとしていることがわかりますが、この場合は_kotlin.collections.List
_であり、解決しません。 setListMapper(MyClass::class, MyClass.serializer())
のようなものを呼び出そうとしましたが、これはシリアル化でのみ機能します(lookupSerializerByData
のwrite
メソッドで使用)
_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
を利用していません。