I need to de-serialize optional values from json to the data class in Kotlin, which have Option
types. Example:
data class Sample(val id: Long, val content: Option<String>)
fun main() {
val mapper = ObjectMapper()
val v1 = mapper.readValue("""
{ "id": "1", "content": null }
""".trimIndent(), Sample::class.java)
val v2 = mapper.readValue("""
{ "id": "2", "content": "Some content" }
""".trimIndent(), Sample::class.java)
assert(v1.id == 1)
assert(v1.content == Option.empty())
assert(v2.id == 2)
assert(v2.content == Option.just("Some content"))
}
I'm struggling to write correct version of deserializer for this use case. Here is what I've tried:
class OptionDeserializer<T>(private val clazz: Class<T>) : StdDeserializer<Option<T>>(clazz) {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Option<T> {
val value = p?.codec?.readValue(p, clazz)
return if (value == null) Option.empty() else Option.just(value)
}
}
fun main() {
val mapper = ObjectMapper()
val module = SimpleModule("Option")
module.addDeserializer(Option::class.java,
OptionDeserializer(Option::class.java))
mapper.registerModule(module)
val v1 = mapper.readValue("""
{ "id": "1", "content": "Some content" }
""".trimIndent(), Sample::class.java)
assert(v1.id == 1)
assert(v1.content == Option.just("Some content"))
}
But this doesn't work and throws error:
Cannot construct instance of
$Sample
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{ "id" : "1", "content" : "Some content" }"; line: 2, column: 3] com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of$Sample
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)"{ "id" : "1", "content" : "Some content" }"; line: 2, column: 3] at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452) at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1028) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
How to get jackson to work with the Option
type from arrow-kt
?
Option.fromNullable()
instead of manual null checking. – galcyurio