Hello. I'm trying to deserialize into a LocalDate object from a JSON ISO string (e.g. "2021-10-01")....
j
Hello. I'm trying to deserialize into a LocalDate object from a JSON ISO string (e.g. "2021-10-01"). I'm using
kotlinx.serializable
On the way out (i.e. serializing) it works fine with this
Copy code
@Serializable
data class Task(
    var id: Int? = null, val title: String, val detail: String? = null,
    @Contextual
    val dueDate: LocalDate? = null
)
But when I try to
Copy code
val task = call.receive<Task>()
in route, then I get an
Serializer for class 'LocalDate' is not found.
I've been through the kotlinx.serialization docs, but I can't see find anything to help.
b
a
Is
LocalDate
from JDK or kotlinx-datetime?
j
Did you remember to setup the serializer context?
Remember? Not really. I did read that, and didn't understand it. I've read it again, and still don't tbh.
Is  
LocalDate
 from JDK or kotlinx-datetime?
It's added via
import java.time.LocalDate
a
@Jonathan Hollingsworth you can write a custom serializer for
LocalDate
and using context serialization bind them together at runtime. Here is a working example:
Copy code
import io.ktor.application.*
import io.ktor.features.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.serialization.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import java.time.LocalDate
import java.time.format.DateTimeFormatter

object LocalDateSerializer : KSerializer<LocalDate> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: LocalDate) {
        val result = value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))
        encoder.encodeString(result)
    }

    override fun deserialize(decoder: Decoder): LocalDate {
        return LocalDate.parse(decoder.decodeString())
    }
}

fun main(args: Array<String>) {
    embeddedServer(Netty, port = 5050) {
        install(ContentNegotiation) {
            json(Json {
                serializersModule = SerializersModule {
                    contextual(LocalDate::class, LocalDateSerializer)
                }
            })
        }

        routing {
            post("/") {
                val t = call.receive<Task>()
                call.respondText { t.dueDate!!.format(DateTimeFormatter.ISO_DATE) }
            }
        }

    }.start()
}

@Serializable
data class Task(
    var id: Int? = null,
    @Contextual
    val dueDate: LocalDate? = null
)
j
Oh, that looks amazing. Thank you. I'm going to study the heck out of this
I also think I could have stared at this for about three days and not figured that out. 😞
Yep, that totally nailed it. Thank you again
👍 1
2916 Views