Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 855
jchtd Avatar asked Mar 23 '20 12:03

jchtd


People also ask

Does Kotlinx serialization use reflection?

Kotlin Serialization does not use reflection, so you cannot accidentally deserialize a class which was not supposed to be serializable. We fix it by adding the @Serializable annotation.

Why is Kotlinx serialized?

kotlinx. serialization provides sets of libraries for all supported platforms – JVM, JavaScript, Native – and for various serialization formats – JSON, CBOR, protocol buffers, and others. You can find the complete list of supported serialization formats below. All Kotlin serialization libraries belong to the org.

What is data serialization in Kotlin?

In Kotlin, data serialization tools are available in a separate component, kotlinx.serialization. It consists of two main parts: the Gradle plugin – org.jetbrains.kotlin.plugin.serialization and the runtime libraries.

Is it possible to use kotlinx serialization with retrofit?

(Kotlinx library is multiplatform library you can use it with Kotlin multiplatform in your JS, iOS, Android, Web project). If you use it in your Android project and you are using Retrofit, then there is a good news there is an official lib to use Kotlinx serialization with Retrofit (thanks for Jake Wharton !!!).

How to implement serialization in HashMap?

HashMap is a concrete class which implements serializable. You can use any concrete sub class of Map which implements serializable val filters: HashMap<String, Any?> = HashMap () filters.put ("a", 2)

What is serialization and deserialization?

Serialization is the process of converting data used by an application to a format that can be transferred over a network or stored in a database or a file. In turn, deserialization is the opposite process of reading data from an external source and converting it into a runtime object.


1 Answers

@file:UseSerializers(LocalDateSerializer::class)

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

like image 180
Lena Bru Avatar answered Oct 16 '22 11:10

Lena Bru