Kotlinx 序列化 - 忽略空值的自定义序列化程序
Kotlinx Serialization - Custom serializer to ignore null value
假设我有一个 class 像:
@Serializable
data class MyClass(
@SerialName("a") val a: String?,
@SerialName("b") val b: String
)
假设 a
是 null
并且 b
的值是 "b value",那么 Json.stringify(MyClass.serializer(), this)
产生:
{ "a": null, "b": "b value" }
基本上如果 a
是 null
,我想得到这个:
{ "b": "b value" }
根据一些研究,我发现这目前无法通过 Kotlinx 序列化开箱即用,因此我试图构建一个自定义序列化程序以显式忽略 null
值。我遵循了 here 的指南,但无法做出正确的。
有人可以帮我解释一下吗?谢谢。
试试这个(未测试,仅基于改编示例):
@Serializable
data class MyClass(val a: String?, val b: String) {
@Serializer(forClass = MyClass::class)
companion object : KSerializer<MyClass> {
override val descriptor: SerialDescriptor = object : SerialClassDescImpl("MyClass") {
init {
addElement("a")
addElement("b")
}
}
override fun serialize(encoder: Encoder, obj: MyClass) {
encoder.beginStructure(descriptor).run {
obj.a?.let { encodeStringElement(descriptor, 0, obj.a) }
encodeStringElement(descriptor, 1, obj.b)
endStructure(descriptor)
}
}
override fun deserialize(decoder: Decoder): MyClass {
var a: String? = null
var b = ""
decoder.beginStructure(descriptor).run {
loop@ while (true) {
when (val i = decodeElementIndex(descriptor)) {
CompositeDecoder.READ_DONE -> break@loop
0 -> a = decodeStringElement(descriptor, i)
1 -> b = decodeStringElement(descriptor, i)
else -> throw SerializationException("Unknown index $i")
}
}
endStructure(descriptor)
}
return MyClass(a, b)
}
}
}
在 JsonConfiguration
中使用 encodeDefaults = false
属性 并且它不会序列化空值(或其他可选值)
JsonConfiguration
已 弃用 支持 Json {}
生成器,因为 kotlinx.serialization 1.0.0-RC 根据其 changelog.
现在你必须这样编码:
val json = Json { encodeDefaults = false }
val body = json.encodeToString(someSerializableObject)
您可以使用explicitNulls = false
示例:
@OptIn(ExperimentalSerializationApi::class)
val format = Json { explicitNulls = false }
@Serializable
data class Project(
val name: String,
val language: String,
val version: String? = "1.3.0",
val website: String?,
)
fun main() {
val data = Project("kotlinx.serialization", "Kotlin", null, null)
val json = format.encodeToString(data)
println(json) // {"name":"kotlinx.serialization","language":"Kotlin"}
}
https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#explicit-nulls
假设我有一个 class 像:
@Serializable
data class MyClass(
@SerialName("a") val a: String?,
@SerialName("b") val b: String
)
假设 a
是 null
并且 b
的值是 "b value",那么 Json.stringify(MyClass.serializer(), this)
产生:
{ "a": null, "b": "b value" }
基本上如果 a
是 null
,我想得到这个:
{ "b": "b value" }
根据一些研究,我发现这目前无法通过 Kotlinx 序列化开箱即用,因此我试图构建一个自定义序列化程序以显式忽略 null
值。我遵循了 here 的指南,但无法做出正确的。
有人可以帮我解释一下吗?谢谢。
试试这个(未测试,仅基于改编示例):
@Serializable
data class MyClass(val a: String?, val b: String) {
@Serializer(forClass = MyClass::class)
companion object : KSerializer<MyClass> {
override val descriptor: SerialDescriptor = object : SerialClassDescImpl("MyClass") {
init {
addElement("a")
addElement("b")
}
}
override fun serialize(encoder: Encoder, obj: MyClass) {
encoder.beginStructure(descriptor).run {
obj.a?.let { encodeStringElement(descriptor, 0, obj.a) }
encodeStringElement(descriptor, 1, obj.b)
endStructure(descriptor)
}
}
override fun deserialize(decoder: Decoder): MyClass {
var a: String? = null
var b = ""
decoder.beginStructure(descriptor).run {
loop@ while (true) {
when (val i = decodeElementIndex(descriptor)) {
CompositeDecoder.READ_DONE -> break@loop
0 -> a = decodeStringElement(descriptor, i)
1 -> b = decodeStringElement(descriptor, i)
else -> throw SerializationException("Unknown index $i")
}
}
endStructure(descriptor)
}
return MyClass(a, b)
}
}
}
在 JsonConfiguration
中使用 encodeDefaults = false
属性 并且它不会序列化空值(或其他可选值)
JsonConfiguration
已 弃用 支持 Json {}
生成器,因为 kotlinx.serialization 1.0.0-RC 根据其 changelog.
现在你必须这样编码:
val json = Json { encodeDefaults = false }
val body = json.encodeToString(someSerializableObject)
您可以使用explicitNulls = false
示例:
@OptIn(ExperimentalSerializationApi::class)
val format = Json { explicitNulls = false }
@Serializable
data class Project(
val name: String,
val language: String,
val version: String? = "1.3.0",
val website: String?,
)
fun main() {
val data = Project("kotlinx.serialization", "Kotlin", null, null)
val json = format.encodeToString(data)
println(json) // {"name":"kotlinx.serialization","language":"Kotlin"}
}
https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#explicit-nulls