Kotlinx.serialization: Android Kotlin Serialization - Can't locate argument-less serializer for class java.util.UUID (Kotlin reflection is not available)

Created on 16 Jan 2019  路  3Comments  路  Source: Kotlin/kotlinx.serialization

Just trying to understand Kotlin Serialization a bit better, then I couldn't figure out what went wrong.
Here's the code, just a simple encode and decode.

open class Human(private val uuid: UUID = UUID.randomUUID())

    @Serializable
    class User(val name: String, val age: Int) : Human()

    @Test
    fun decodeEncodeSerialization() {
        val user = User(
            "Aerith Gainsborough",
            25
        )
        val userJson = JSON.stringify(User.serializer(), user)
        val userObject = JSON.parse(User.serializer(), userJson)
    }

kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class java.util.UUID (Kotlin reflection is not available). For generic classes, such as lists, please provide serializer explicitly.

Here's the problem with the UUID class, if I'm using a String. It'll be fine.
Is it because java.util.UUID implements java.io.Serializable?
Any idea what went wrong here?

Most helpful comment

Managed to got it to work. Just gonna put here for future references.
Thanks mate!

    @Serializable
    open class Human(
        @Serializable(with = UUIDSerializer::class)
        var uuid: UUID = UUID.randomUUID()
    )

    @Serializer(forClass = UUID::class)
    object UUIDSerializer : KSerializer<UUID> {
        override val descriptor: SerialDescriptor
            get() = StringDescriptor.withName("UUID")

        override fun serialize(output: Encoder, obj: UUID) {
            output.encodeString(obj.toString())
        }

        override fun deserialize(input: Decoder): UUID {
            return UUID.fromString(input.decode())
        }
    }

    @Serializable
    class User(val name: String, val age: Int) : Human()

    @Test
    fun decodeEncodeSerialization() {
        val user = User("Aerith Gainsborough", 25)

        val userJson = JSON.stringify(User.serializer(), user)
        val userObject = JSON.parse(User.serializer(), userJson)
    }

All 3 comments

It's telling you what's wrong. You need to provide a custom serializer than can convert UUID to a primitive that exists in JSON (such as string). Details are here: https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/custom_serializers.md

Managed to got it to work. Just gonna put here for future references.
Thanks mate!

    @Serializable
    open class Human(
        @Serializable(with = UUIDSerializer::class)
        var uuid: UUID = UUID.randomUUID()
    )

    @Serializer(forClass = UUID::class)
    object UUIDSerializer : KSerializer<UUID> {
        override val descriptor: SerialDescriptor
            get() = StringDescriptor.withName("UUID")

        override fun serialize(output: Encoder, obj: UUID) {
            output.encodeString(obj.toString())
        }

        override fun deserialize(input: Decoder): UUID {
            return UUID.fromString(input.decode())
        }
    }

    @Serializable
    class User(val name: String, val age: Int) : Human()

    @Test
    fun decodeEncodeSerialization() {
        val user = User("Aerith Gainsborough", 25)

        val userJson = JSON.stringify(User.serializer(), user)
        val userObject = JSON.parse(User.serializer(), userJson)
    }

Since last comment there were a lot of signatures changed, so the current UUID Serializer is:

@ExperimentalSerializationApi
@Serializer(forClass = UUID::class)
object UUIDSerializer : KSerializer<UUID> {
    override val descriptor: SerialDescriptor
        get() = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: UUID) {
        encoder.encodeString(value.toString())
    }

    override fun deserialize(decoder: Decoder): UUID {
        return UUID.fromString(decoder.decodeString())
    }
}
Was this page helpful?
0 / 5 - 0 ratings