我正在努力了解如何使用实验性{}
库解析空对象kotlinx.serialization
。实际上,当API响应可能是其中之一时,就会出现这种情况;
{
"id": "ABC1",
"status": "A_STATUS"
}
或
{}
我用作序列化程序的数据结构是;
data class Thing(val id: String = "", val status: String = "")
这用@kotlinx.serialization.Serializable
注释,并在API客户端库中用于在原始API响应和数据模型之间进行编组。默认值告诉序列化库该字段是可选的,并替换了Kotlin 1.3.30之前的@Optional
方法。
最后,我正在使用的kotlinx.serialization.json.Json
解析器具有通过使用nonstrict
模板应用的配置。
如何定义一个可以使用kotlinx.serialization
解析空对象和预期数据类型的序列化程序?我需要编写自己的KSerialiser
还是我缺少的配置?理想情况下,应该将空对象忽略/解析为null
?
使用Thing
数据类解析空对象时遇到的错误是;
Field 'id' is required, but it was missing
答案 0 :(得分:0)
因此,这归因于kotlinCompilerClasspath
具有不同版本的kotlin(1.3.21,而不是1.3.31)。
有趣的是,这是由于我在配置gradle插件项目以不指定kotlin-dsl
插件的版本时遵循的建议。
明确依赖我需要的版本来修复kotlinx.serialisation
的行为(未更改主线代码)
答案 1 :(得分:0)
是的,理想情况下 null
而不是 {}
更便于解析,但有时您只需要使用后端发送给您的内容
我想到了两种解决方案。
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class ThingMapSerializerTest {
@Test
fun `should deserialize to non empty map`() {
val thingMap: Map<String, String> =
Json.decodeFromString("""{"id":"ABC1","status":"A_STATUS"}""")
assertTrue(thingMap.isNotEmpty())
assertEquals("ABC1", thingMap["id"])
assertEquals("A_STATUS", thingMap["status"])
}
@Test
fun `should deserialize to empty map`() {
val thingMap: Map<String, String> = Json.decodeFromString("{}")
assertTrue(thingMap.isEmpty())
}
}
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationException
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.serialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.encoding.decodeStructure
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Test
class ThingSerializerTest {
@Test
fun `should deserialize to thing`() {
val thing: OptionalThing =
Json.decodeFromString(
OptionalThing.ThingSerializer,
"""{"id":"ABC1","status":"A_STATUS"}"""
)
assertEquals(OptionalThing.Thing(id = "ABC1", status = "A_STATUS"), thing)
}
@Test
fun `should deserialize to empty`() {
val thing: OptionalThing =
Json.decodeFromString(OptionalThing.ThingSerializer, "{}")
assertEquals(OptionalThing.Empty, thing)
}
sealed class OptionalThing {
data class Thing(val id: String = "", val status: String = "") : OptionalThing()
object Empty : OptionalThing()
object ThingSerializer : KSerializer<OptionalThing> {
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("your.app.package.OptionalThing") {
element("id", serialDescriptor<String>(), isOptional = true)
element("status", serialDescriptor<String>(), isOptional = true)
}
override fun deserialize(decoder: Decoder): OptionalThing {
decoder.decodeStructure(descriptor) {
var id: String? = null
var status: String? = null
loop@ while (true) {
when (val index = decodeElementIndex(descriptor)) {
CompositeDecoder.DECODE_DONE -> break@loop
0 -> id = decodeStringElement(descriptor, index = 0)
1 -> status = decodeStringElement(descriptor, index = 1)
else -> throw SerializationException("Unexpected index $index")
}
}
return if (id != null && status != null) Thing(id, status)
else Empty
}
}
override fun serialize(encoder: Encoder, value: OptionalThing) {
TODO("Not implemented, not needed")
}
}
}
}
当 'Thing' 是 json 对象中的一个字段时:
"thing":{"id":"ABC1","status":"A_STATUS"} // could be {}
您可以像这样注释属性:
@Serializable(with = OptionalThing.ThingSerializer::class)
val thing: OptionalThing
测试:
classpath "org.jetbrains.kotlin:kotlin-serialization:1.4.10"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"