https://kotlinlang.org logo
#jackson-kotlin
Title
# jackson-kotlin
d

Dariusz Kuc

07/20/2020, 5:50 PM
hello 👋 JSON fields can have 3 states ->
undefined
(field is omitted),
null
(field=null) and also can have a
value
(field=value). Within JVM we either have value or no-value (i.e.
null
) so we are trying to represent those 3 states using Kotlin sealed classes - something along the lines
Copy code
sealed class OptionallyDefined<T> {
    object Undefined : OptionallyDefined<Nothing>()
    data class Defined<T>(val data: T) : OptionallyDefined<T>()
}
Unfortunately cannot get the deserialization to work. I tried using custom serializer (i.e.
@JsonDeserialize(using = NullAwareDeserializer::class)
) but cannot get it to work correctly. Any pointers would be greatly appreciated!
1
@Shane Myrick fyi
👍 1
j

Joe

07/22/2020, 3:38 AM
this appears to work, using `@JsonCreator`:
Copy code
sealed class OptionallyDefined<T> {
    class Undefined<T> : OptionallyDefined<T>()
    data class Defined<T>(val data: T?) : OptionallyDefined<T>()
    companion object {
        @JvmStatic
        @JsonCreator
        fun <T> getOptDefined(input: Map<String, T>): OptionallyDefined<T> {
            return if (input.containsKey("data")) {
                OptionallyDefined.Defined(input["data"])
            } else {
                OptionallyDefined.Undefined()
            }
        }
    }
}

fun main() {
    val mapper = ObjectMapper()
    val x = OptionallyDefined.Defined<Int?>(1)
    val y: OptionallyDefined<Int?> = OptionallyDefined.Undefined()
    val z = OptionallyDefined.Defined<Int?>(null)
    println(mapper.writeValueAsString(x))
    println(mapper.writeValueAsString(y))
    println(mapper.writeValueAsString(z))
    println(mapper.readValue<OptionallyDefined<Int?>>("{\"data\":1}"))
    println(mapper.readValue<OptionallyDefined<Int?>>("{}"))
    println(mapper.readValue<OptionallyDefined<Int?>>("{\"data\":null}"))
}
d

Dariusz Kuc

07/22/2020, 2:43 PM
👍
it gets slightly more complex as
Defined
is just a wrapper (similar to
Optional
)
so using JDK 8 module, we can do
Copy code
data class TestResult(val maybe: Optional<String?>? = null)

fun main() {
    val mapper = jacksonObjectMapper()
    mapper.registerModule(Jdk8Module())

    val undefined = "{}"
    val nullValue = """{ "maybe": null }"""
    val value = """{ "maybe": "actual" }"""

    val undefinedValue = mapper.readValue(undefined, TestResult::class.java)
    println(undefinedValue)
    val explicitNull = mapper.readValue(nullValue, TestResult::class.java)
    println(explicitNull)
    val withValue = mapper.readValue(value, TestResult::class.java)
    println(withValue)
}
*note the explicit nullability of optional and default value for it
👍 1
3 Views