How to serialize a generic class with kontlinx.serialization?

3.5k views Asked by At

I have followed a tutorial to create a custom serialization for my generic class. But I am still stacked with error:

SerializationException: Serializer for class 'ApiResponse' is not found. Mark the class as @Serializable or provide the serializer explicitly.

My ApiResponse class looks like this:

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

And ApiResponseSerializer, that is used in annotation above is:

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)
        }
    }
}

Then, when I’m trying to serialize my data object, I receive an exception I’ve mentioned above.

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

Can someone tell me where I’m wrong? Thank you.

3

There are 3 answers

0
SorrowBeaver On

It seems to be kapt's bug.

I found this comment from the serialization repository :

However, due to the mentioned kapt issue, it's impossible for now. Probably, a viable workaround can be to move models and serializers to the separate Gradle module, which is not processed by kapt.

And there are more issues about this problem :

0
Stephan Windmüller On

kotlinx.serialization uses a specific plugin to generate serializers. If you start your code directly in the IDE (e.g. via the main method), the plugin is not used.

To ensure that generated serializers are available on the classpath, try calling your code from a unit test and start this test with the appropriate Gradle task.

0
P. Savrov On

The code in the question was good, the program fails due to bad cache or something else.