jchtd
jchtd

Reputation: 101

Is there a way to serialize a map in Kotlinx-Serialization

I'm using Kotlin 1.3.10 (and bound to this version) and Kotlinx-Serialization 0.13 and I'm having trouble with serializing a map in Kotlinx-Serialization.

I have the following code:

@Serializer(forClass = LocalDate::class)
object LocalDateSerializer : KSerializer<LocalDate> {
    private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
    override val descriptor: SerialDescriptor
        get() = StringDescriptor.withName("LocalDate")
    override fun serialize(encoder: Encoder, obj: LocalDate) {
        encoder.encodeString(obj.format(formatter))
    }
    override fun deserialize(decoder: Decoder): LocalDate {
        return LocalDate.parse(decoder.decodeString(), formatter)
    }
}

@Serializable
data class MyClass (
    val students: Map<String,LocalDate>
)

@UnstableDefault
@Test
fun decodeEncodeSerialization() {
    val jsonParser = Json(
        JsonConfiguration(
            allowStructuredMapKeys = true
        )
    )
    val mc = MyClass(
        mapOf("Alex" to LocalDate.of(1997,2,23))
        )

    val mcJson = jsonParser.stringify(MyClass.serializer(), mc)
    val mcObject = jsonParser.parse(MyClass.serializer(), mcJson)

    assert(true)
}

There is a red line when inspecting the code which says "Serializer has not been found for 'LocalDate'. To use context serializer as fallback, explicitly annotate type or property with @ContextualSerialization."

With other types of fields, it would have been enough to add @Serialization to it.

@Serializable
data class Student (
    val name: String,
    @Serializable(with = LocalDateSerializer::class)
    val dob: LocalDate
)

But with a map I can't seem to figure out how. I put it above, or beside the object...

@Serializable
data class MyClass (
    val students: Map<String,@Serializable(with = LocalDateSerializer::class) LocalDate> //here
    //or 
    //@Serializable(with = LocalDateSerializer::class)
    //val students2: Map<String, LocalDate> //here 
)

...but tests still fail with

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

And the workaround I have for it is

@Serializable
data class MyClass (
    val students: List<Student>
)
@Serializable
data class Student (
    val name: String,
    @Serializable(with = LocalDateSerializer::class)
    val dob: LocalDate
)

Is there a way I would not resort to the workaround? Thank you!

Upvotes: 9

Views: 6268

Answers (1)

Lena Bru
Lena Bru

Reputation: 13937

@file:UseSerializers(LocalDateSerializer::class)

put this in the file where your object is declared it should use LocalDateSerializer every time it sees Local Date

Upvotes: 1

Related Questions