Kotlinx.serialization: Can you add a serializer for Dates?

Created on 10 Oct 2017  路  10Comments  路  Source: Kotlin/kotlinx.serialization

Hi,
at runtime I get IllegalArgumentException: Can't found internal serializer for class class java.util.Date when I serialize an object that contains a Date.

I tried to write my own KSerializer but I didn't succeed 馃槩

question

Most helpful comment

I know this is closed but I just want to add this here for reference since it seems based on the doc the serialization format is changed and that the first comment on this thread is deprecated.

below works for both timestamp based serialization or if you uncomment the commented lines and comment the duplicates, then it will work using string formatted dates.

please provide feedback if this one isn't efficient or if you have better ideas. i got used to Newtonsoft.JSON from the dotnet world and this never seems to be a huge problem from their, but here it has to be manually written. hoping someday this becomes avaiable by default.

package se.netzon.ekin.serializers

import kotlinx.serialization.*
import kotlinx.serialization.internal.*
import java.util.*

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

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

  override fun deserialize(input: Decoder): Date {
    return Date(input.decodeString().toLong())
  }
}

All 10 comments

You can write your custom serializer for Date in this way:

@Serializable
class DateWrapper(val date: Date)

@Serializer(forClass = Date::class)
object DateSerializer: KSerializer<Date> {
    private val df: DateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS")

    override fun save(output: KOutput, obj: Date) {
        output.writeStringValue(df.format(obj))
    }

    override fun load(input: KInput): Date {
        return df.parse(input.readStringValue())
    }

    override val serialClassDesc: KSerialClassDesc = SerialClassDescImpl("Date")
}

Then, register it at startup of your application: kotlinx.serialization.registerSerializer("java.util.Date", DateSerializer)

And now it should work. Note that JSON.stringify(DateWrapper(Date())) will give you {"date":["Date","11\/10\/2017 11:40:20.265"]} - Date object is wrapped in array with type info, because polymorphic serialization was enabled.

Hey,
thanks for the fast answer. I got trouble to implement your idea, at compile time I have
Error:(17, 18) Conflicting declarations: public open val serialClassDesc: KSerialClassDesc
on the line
override val serialClassDesc: kotlinx.serialization.KSerialClassDesc = SerialClassDescImpl("Date").

I pushed a commit about my try if it can help you https://github.com/olivierperez/crapp/commit/6db87562659a75541fec7f12ae9988b8f2997da2


I've created the KSerializer
https://github.com/olivierperez/crapp/commit/6db87562659a75541fec7f12ae9988b8f2997da2#diff-918c256547830fc9ac551d28b90ca385R1

I've done the registration
https://github.com/olivierperez/crapp/commit/6db87562659a75541fec7f12ae9988b8f2997da2#diff-763ab1f257351c15e9eafd3f6e439e56R10

I try to parse
https://github.com/olivierperez/crapp/commit/6db87562659a75541fec7f12ae9988b8f2997da2#diff-fbc07e78c4dda45d4eb862c43cdf93a2R78


Nothing urges, I was just giving a try to your lib for now ;-)

looks like #10, but it was fixed some time ago. I've copied your serializer and data class, and it works fine. Is this definitely gradle build error? (JPS plugin still has some issues, and highlighting/compilation from IDEA may produce incorrect results)

Unfortunately this doesn't seem to work with the Protobuf backend:

java.util.NoSuchElementException: List is empty.
    at kotlin.collections.CollectionsKt___CollectionsKt.single(_Collections.kt:472)
    at kotlinx.serialization.protobuf.ProtoBuf.getProtoDesc(ProtoBuf.kt:41)
    at kotlinx.serialization.protobuf.ProtoBuf.access$getProtoDesc(ProtoBuf.kt:38)
    at kotlinx.serialization.protobuf.ProtoBuf$ProtobufWriter.getTag(ProtoBuf.kt:67)
    at kotlinx.serialization.protobuf.ProtoBuf$ProtobufWriter.getTag(ProtoBuf.kt:47)
    at kotlinx.serialization.TaggedOutput.writeStringElementValue(Tagged.kt:155)
    at kotlinx.serialization.internal.PolymorphicSerializer.save(Polymorphic.kt:42)
    at kotlinx.serialization.KOutput.writeSerializableValue(Serialization.kt:133)
    at kotlinx.serialization.KOutput.writeSerializableElementValue(Serialization.kt:174)

Should this work for Javascript as well, because I can't get it to work.

My kotlinx(0.1.1) lacks the registerSerializer method

Yes, currently its unavailable on JS platform because it's relying on Java Reflection for registering/unregistering. We are going to eliminate this restriction soon.

Ok. Thanks for the heads-up.

Information about custom serializers updated in latest doc

I know this is closed but I just want to add this here for reference since it seems based on the doc the serialization format is changed and that the first comment on this thread is deprecated.

below works for both timestamp based serialization or if you uncomment the commented lines and comment the duplicates, then it will work using string formatted dates.

please provide feedback if this one isn't efficient or if you have better ideas. i got used to Newtonsoft.JSON from the dotnet world and this never seems to be a huge problem from their, but here it has to be manually written. hoping someday this becomes avaiable by default.

package se.netzon.ekin.serializers

import kotlinx.serialization.*
import kotlinx.serialization.internal.*
import java.util.*

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

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

  override fun deserialize(input: Decoder): Date {
    return Date(input.decodeString().toLong())
  }
}

Current problem is that kotlin multiplatform stdlib does not have a definition of Date. We, however, consider providing additional module to work with standard JVM classes (see #350, WIP )

Was this page helpful?
0 / 5 - 0 ratings