Kotlinx Serialization - пользовательский сериализатор для игнорирования нулевого значения
Скажем, у меня есть такой класс:
@Serializable
data class MyClass(
@SerialName("a") val a: String?,
@SerialName("b") val b: String
)
Предположим, что a
является null
а также b
значение "b значение", тогда Json.stringify(MyClass.serializer(), this)
производит:
{ "a": null, "b": "b value" }
В основном если a
является null
, Я хотел получить вот что:
{ "b": "b value" }
Из некоторых исследований я обнаружил, что в настоящее время это невозможно из коробки с сериализацией Kotlinx, поэтому я пытался создать собственный сериализатор, чтобы явно игнорировать null
ценность. Я следовал руководству отсюда, но не смог составить правильный.
Может кто-нибудь пролить свет на меня? Спасибо.
6 ответов
Попробуйте это (не проверено, просто на основе адаптации примера):
@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)
}
}
}
Вы можете использовать
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
Использовать encodeDefaults = false
собственность в JsonConfiguration
и он не будет сериализовать нули (или другие необязательные значения)
Поскольку я также боролся с этим, позвольте мне поделиться с вами решением, которое я нашел для каждого свойства и не требует создания сериализатора для всего класса.
class ExcludeIfNullSerializer : KSerializer<String?> {
override fun deserialize(decoder: Decoder): String {
return decoder.decodeString()
}
override val descriptor: SerialDescriptor
get() = PrimitiveSerialDescriptor("ExcludeNullString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: String?) {
if (value != null) {
encoder.encodeString(value)
}
}
}
будет работать, как и ожидалось, со следующим классом
@Serializable
class TestDto(
@SerialName("someString")
val someString: String,
@SerialName("id")
@EncodeDefault(EncodeDefault.Mode.NEVER)
@Serializable(with = ExcludeIfNullSerializer::class)
val id: String? = null
)
Обратите внимание, что @EncodeDefault(EncodeDefault.Mode.NEVER) имеет решающее значение здесь, если вы используете JsonBuilder с encodeDefaults = true, так как в этом случае библиотека сериализации все равно добавит ключ json «id», даже если значение поля id равно null, если только используя эту аннотацию.
JsonConfiguration
является устаревшим в пользу
Json {}
builder начиная с kotlinx.serialization 1.0.0-RC согласно его журналу изменений.
Теперь вам нужно написать вот так:
val json = Json { encodeDefaults = false }
val body = json.encodeToString(someSerializableObject)
На данный момент для всех, кто видит этот пост сегодня, значения по умолчанию не сериализованы (см. https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/basic-serialization.md#defaults-are-not- закодировано по умолчанию)
Таким образом, вы просто добавляете, чтобы установить нулевое значение по умолчанию, и оно не будет сериализовано.