Kotlinx Serialization - пользовательский сериализатор для игнорирования нулевого значения

Скажем, у меня есть такой класс:

@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. Я следовал руководству из здесь, но не смог правильный.

Может кто-нибудь пролить свет на меня? Спасибо.


person H.Nguyen    schedule 23.09.2019    source источник


Ответы (3)


Попробуйте это (не проверено, просто на основе адаптации примера):

@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)
        }
    }
}
person Alexey Romanov    schedule 23.09.2019

Используйте свойство encodeDefaults = false в JsonConfiguration, и оно не будет сериализовать нули (или другие необязательные значения)

person kissed    schedule 28.05.2020
comment
Это работает только в том случае, если вы хотите игнорировать все значения по умолчанию, что не всегда так. Одним из примеров является WooCommerce, где есть вариант_id, если он не существует, вы не должны передавать его в заказ как элемент строки, поэтому идеальный путь - установить для него значение null, но WooCommerce не принимает значение null в качестве значения. В этом случае для более мелкозернистого элемента управления было бы неплохо сказать игнорировать это значение, если оно не было установлено, или игнорировать это значение, если оно равно нулю. - person CodyEngel; 09.12.2020

JsonConfiguration устарел в пользу Json {} builder, поскольку kotlinx.serialization 1.0.0-RC в соответствии с его журнал изменений.

Теперь вам нужно написать такой код:

val json = Json { encodeDefaults = false }
val body = json.encodeToString(someSerializableObject)
person Jing Li    schedule 22.11.2020