Ktor 自定义 json 对象反序列化
Ktor custom json object deserialization
我是Ktor新手,Retrofit出身,想贴图这个json:
{
"key1": "value1",
"key2": "value2",
...
}
到(实际上我不需要映射 json 本身,只需要反序列化版本):
[
{"key1": "value1"},
{"key2": "value2"},
...
]
@Serializable
data class MyObject(
val member1: String,
val member2: String
)
我在官方文档中看到的示例并没有多大帮助,所以我尝试了类似的方法:
@InternalSerializationApi
object CustomDeserializer : DeserializationStrategy<List<MyObject>> {
@ExperimentalSerializationApi
override val descriptor = buildSerialDescriptor("MyObject", PolymorphicKind.OPEN){
element("key", String.serializer().descriptor)
element("value", String.serializer().descriptor)
}
@ExperimentalSerializationApi
override fun deserialize(decoder: Decoder): List<MyObject> = decoder.decodeStructure(descriptor) {
val result = ArrayList<MyObject>()
loop@ while (true) {
val index = decodeElementIndex(descriptor)
if (index == DECODE_DONE) {
break@loop
} else if (index > 1) {
throw SerializationException("Unexpected index $index")
} else {
result.add(MyObject(decodeStringElement(descriptor, index = 0), decodeStringElement(descriptor, index = 1)))
}
}
return result
}
}
问题:
- 我走的路是否正确,或者有更好的方法可以实现吗?
- 如何将此添加到我的客户端? (可能仅针对特定请求)
ps:这就是我使用 Gson 的方式(忽略 Java 中的事实):
public class MyObjectConverterFactory implements JsonDeserializer<List<MyObject>> {
@Override
public List<MyObject> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<MyObject> res = new ArrayList<>();
if (json != null && json.getAsJsonObject() != null) {
JsonObject object = json.getAsJsonObject();
Set<String> keys = object.keySet();
for (String key : keys) {
res.add(new MyObject(key, object.get(key).getAsString()));
}
}
return res;
}
}
据我从 GSON 实现中得到的信息,您需要从 JSON
反序列化
{"key1":"value1","key2":"value2", ...}
进入
listOf(MyObject(member1="key1", member2="value1"), MyObject(member1="key2", member2="value2"), ...)
kotlinx.serialization
也可以:
object MyObjectListSerializer : JsonTransformingSerializer<List<MyObject>>(ListSerializer(MyObject.serializer())) {
override fun transformDeserialize(element: JsonElement) =
JsonArray((element as JsonObject).entries.map { (k, v) ->
buildJsonObject {
put("member1", k)
put("member2", v)
}
})
}
用法(普通kotlinx.serialization):
val result = Json.decodeFromString(MyObjectListSerializer, "{\"key1\":\"value1\",\"key2\":\"value2\"}")
用法(使用 Ktor 客户端):
val client = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer(Json {
serializersModule = SerializersModule { contextual(MyObjectListSerializer) }
})
}
}
val result = client.get<List<MyObject>>("http://localhost:8000/myObj")
我是Ktor新手,Retrofit出身,想贴图这个json:
{
"key1": "value1",
"key2": "value2",
...
}
到(实际上我不需要映射 json 本身,只需要反序列化版本):
[
{"key1": "value1"},
{"key2": "value2"},
...
]
@Serializable
data class MyObject(
val member1: String,
val member2: String
)
我在官方文档中看到的示例并没有多大帮助,所以我尝试了类似的方法:
@InternalSerializationApi
object CustomDeserializer : DeserializationStrategy<List<MyObject>> {
@ExperimentalSerializationApi
override val descriptor = buildSerialDescriptor("MyObject", PolymorphicKind.OPEN){
element("key", String.serializer().descriptor)
element("value", String.serializer().descriptor)
}
@ExperimentalSerializationApi
override fun deserialize(decoder: Decoder): List<MyObject> = decoder.decodeStructure(descriptor) {
val result = ArrayList<MyObject>()
loop@ while (true) {
val index = decodeElementIndex(descriptor)
if (index == DECODE_DONE) {
break@loop
} else if (index > 1) {
throw SerializationException("Unexpected index $index")
} else {
result.add(MyObject(decodeStringElement(descriptor, index = 0), decodeStringElement(descriptor, index = 1)))
}
}
return result
}
}
问题:
- 我走的路是否正确,或者有更好的方法可以实现吗?
- 如何将此添加到我的客户端? (可能仅针对特定请求)
ps:这就是我使用 Gson 的方式(忽略 Java 中的事实):
public class MyObjectConverterFactory implements JsonDeserializer<List<MyObject>> {
@Override
public List<MyObject> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
List<MyObject> res = new ArrayList<>();
if (json != null && json.getAsJsonObject() != null) {
JsonObject object = json.getAsJsonObject();
Set<String> keys = object.keySet();
for (String key : keys) {
res.add(new MyObject(key, object.get(key).getAsString()));
}
}
return res;
}
}
据我从 GSON 实现中得到的信息,您需要从 JSON
反序列化{"key1":"value1","key2":"value2", ...}
进入
listOf(MyObject(member1="key1", member2="value1"), MyObject(member1="key2", member2="value2"), ...)
kotlinx.serialization
也可以:
object MyObjectListSerializer : JsonTransformingSerializer<List<MyObject>>(ListSerializer(MyObject.serializer())) {
override fun transformDeserialize(element: JsonElement) =
JsonArray((element as JsonObject).entries.map { (k, v) ->
buildJsonObject {
put("member1", k)
put("member2", v)
}
})
}
用法(普通kotlinx.serialization):
val result = Json.decodeFromString(MyObjectListSerializer, "{\"key1\":\"value1\",\"key2\":\"value2\"}")
用法(使用 Ktor 客户端):
val client = HttpClient {
install(JsonFeature) {
serializer = KotlinxSerializer(Json {
serializersModule = SerializersModule { contextual(MyObjectListSerializer) }
})
}
}
val result = client.get<List<MyObject>>("http://localhost:8000/myObj")