Как сериализовать универсальный класс с помощью kontlinx.serialization?

#kotlin #serialization #kotlinx.serialization

#kotlin #сериализация #kotlinx.serialization

Вопрос:

Я следовал руководству по созданию пользовательской сериализации для моего универсального класса. Но я все еще сталкиваюсь с ошибкой:

Исключение SerializationException: сериализатор для класса ‘ApiResponse’ не найден. Пометьте класс как @Serializable или явно укажите сериализатор.

Мой класс ApiResponse выглядит следующим образом:

 @Serializable(with = ApiResponseSerializer::class)
class ApiResponse<T>(
    @SerialName("data")
    val data: T? = null,
    @SerialName("error")
    val error: ApiError? = null
)
  

И ApiResponseSerializer, который используется в аннотации выше, является:

 class ApiResponseSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<ApiResponse<T>> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ApiResponseDataSerializer") {
        val dataDescriptor = dataSerializer.descriptor
        element("data", dataDescriptor)
        element("error", ApiError.serializer().descriptor)
    }
    override fun deserialize(decoder: Decoder): ApiResponse<T> =
        decoder.decodeStructure(descriptor) {
            var data: T? = null
            var error: ApiError? = null
            loop@ while (true) {
                when (val i = decodeElementIndex(descriptor)) {
                    0 -> data = decodeSerializableElement(descriptor, i, dataSerializer)
                    1 -> error = decodeSerializableElement(descriptor, i, ApiError.serializer())
                    CompositeDecoder.DECODE_DONE -> break
                    else -> throw SerializationException("Unknown index $i")
                }
            }
            ApiResponse(data, error)
        }
    override fun serialize(encoder: Encoder, value: ApiResponse<T>) {
        encoder.encodeStructure(descriptor) {
            encodeNullableSerializableElement(descriptor, 0, dataSerializer, value.data)
            encodeNullableSerializableElement(descriptor, 1, ApiError.serializer(), value.error)
        }
    }
}
  

Затем, когда я пытаюсь сериализовать свой объект данных, я получаю исключение, о котором я упоминал выше.

 Json.encodeToString(ApiResponse(data = response.data))
---- OR ----
Json.encodeToString(ApiResponse.serializer(T::class.serializer()), ApiResponse(data = response.data))
  

Может кто-нибудь сказать мне, где я ошибаюсь? Спасибо.

Комментарии:

1. Отлично работает на моей машине для Json.encodeToString(ApiResponse(data = "some string")) . Что это за тип response.data ? Помечен ли он @Serializable аннотацией?

2. В чем смысл @loop label ?

3. В моем случае данные могут быть представлены любым классом данных с @Serializable аннотацией. @loop Аннотация появляется в документе. к KSerializer классу и, насколько я понимаю, отмечает место, куда программа должна возвращаться в случае break . подробнее: kotlinlang.org/docs/reference / … P.S. теперь это работает. Возможно, это было из-за плохого кэша или чего-то еще. В любом случае спасибо за ваш тест и поддержку

Ответ №1:

Код в вопросе был хорошим, программа завершается сбоем из-за плохого кэша или чего-то еще.

Ответ №2:

Похоже, это ошибка kapt.

Я нашел этот комментарий из репозитория сериализации :

Однако из-за упомянутой проблемы kapt на данный момент это невозможно. Вероятно, жизнеспособным обходным путем может быть перемещение моделей и сериализаторов в отдельный модуль Gradle, который не обрабатывается kapt.

И есть еще вопросы по этой проблеме :

Ответ №3:

kotlinx.serialization использует специальный плагин для создания сериализаторов. Если вы запускаете свой код непосредственно в IDE (например, с помощью main метода), плагин не используется.

Чтобы убедиться, что сгенерированные сериализаторы доступны в пути к классу, попробуйте вызвать свой код из модульного теста и запустить этот тест с соответствующей задачей Gradle .