@SerialInfo - Как управлять пользовательскими последовательными аннотациями с сериализацией Kotlinx?

Документация по сериализации Kotlinx

Согласно с Kotlinx.serializationопределяемые пользователем аннотаций документ:

"В процессе сериализации / десериализации ваш собственный класс аннотации доступен вSerialDescriptorобъект ":

override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
    val annotations = desc.getElementAnnotations(index)
    ...
}

Что я хочу сделать

мне нужно @Transient эквивалентно, но условно:

  • классический способ, где: Json.stringify(serializer, myClass) работает как обычно.
  • пользовательский способ, где: Json.stringify(customSerializer, myClass) вернет обычный json, но исключая все @MyAnnotation-помеченные значения.

Вот мой код

@SerialInfo
@Target(AnnotationTarget.PROPERTY)
annotation class CustomAnnotation

@Serializable
data class MyClass(val a: String, @CustomAnnotation val b: Int = -1)

И я хотел бы создать собственный сериализатор и добиться чего-то вроде

override fun encodeElement(desc: SerialDescriptor, index: Int): Boolean {
    val isTaggedAsCustomAnnotation = desc.getElementAnnotations(index).any{ it is CustomAnnotation }
    val myCondition = mySerializer.getMyConditionBlablabla

    if(myCondition && isTaggedAsCustomAnnotation) {
        encode()    
    }
    ...
}

Что я нашел

abstract class ElementValueEncoder : Encoder, CompositeEncoder {
    ...
    open fun encodeElement(desc: SerialDescriptor, index: Int): Boolean = true
}

Но я не знаю, как я могу создать собственный сериализатор, чтобы переопределить эту функцию. Encoder.encodeElement. Где я могу получить доступ к ElementValueEncoder в настраиваемом сериализаторе?

Я также нашел этот образец демонстрации в репозитории github kotlinx.serialization. Он используетTaggedEncoder & TaggedDecoder где я могу отменить encodeTaggedValue. Но и здесь я не знаю, как использовать этот кодировщик / декодер в процессе сериализации / десериализации.

в заключение

Где я могу отменить fun encodeElement(desc: SerialDescriptor, index: Int): Boolean, и как я могу обрабатывать свою собственную аннотацию сериализации?

Спасибо!!

1 ответ

Решение

Прежде всего, вам нужно понять разницу между сериализатором и кодировщиком. Сериализатор (представленныйKSerializer) определяет, как выглядит ваш класс, а Encoder (представленный, например, JsonOutput) определяет, как данные будут записываться. Вы можете найти дополнительную информацию по этой теме здесь: https://github.com/Kotlin/KEEP/blob/master/proposals/extensions/serialization.md.

Таким образом, функция настраиваемых аннотаций в основном используется для предоставления информации о формате для Encoder. Типичное использование такой аннотации:ProtoId - идентификатор свойства, специфичный для формата protobuf, который должен распознаваться ProtobufEncoder. Такие аннотации обычно определяются авторами формата вместе с их кодировщиками.

Как я вижу, вы хотите использовать уже существующий кодировщик (формат JSON), поэтому переопределите encodeElementневозможно, поскольку кодировщики Json не могут быть разделены на подклассы. Я бы посоветовал вам использовать собственный сериализатор json transofrming для достижения вашей цели. К сожалению, в настоящее время kotlinx.serialization не имеет механизма для обобщения такого преобразования, поэтому вам необходимо написать такой сериализатор для каждого класса.

Другие вопросы по тегам