Pluggable Kotlin utilities for type-safe JSON encoding with Jackson.
Sealed-class based polymorphic type JSON encoding.
sealed class Option<out T> {
companion object : Polymorphic // Implement `Polymorphic` to handle this as a polymorphic type
}
data class Some<out T>(val value: T) : Option<T>()
object None : Option<Nothing>() {
override fun toString() = "None"
}
data class Foo(val bar: Boolean)
fun main() {
val mapper = jacksonObjectMapper().registerModule(PolymorphicModule())
println(mapper.writeValueAsString(Some(30))) // {"type":"Some","value":30}
println(mapper.writeValueAsString(Some(Foo(true)))) // {"type":"Some","value":{"bar":true}}
println(mapper.writeValueAsString(None)) // {"type":"None"}
println(mapper.readValue<Option<String>>("""{"type":"Some","value":"abc"}""")) // Some(value=abc)
println(mapper.readValue<Option<Foo>>("""{"type":"Some","value":{"bar":true}}""")) // Some(value=Foo(bar=true))
println(mapper.readValue<Option<String>>("""{"type":"None"}""")) // None
}
Gradle Kotlin DSL
repositories {
mavenCentral()
maven("https://jitpack.io")
}
dependencies {
implementation("io.github.justincase-jp.jackson-kotlin-commons", "polymorphic", VERSION)
}
sealed class Identity {
companion object : Polymorphic {
override val typeKey = "role"
override val KClass<out Any>.typeName
get() = simpleName?.lowercase(US) ?: throw IllegalArgumentException(toString())
}
}
data class User(val id: String) : Identity()
data class Admin(val id: String) : Identity()
fun main() {
val mapper = jacksonObjectMapper().registerModule(PolymorphicModule())
println(mapper.writeValueAsString(User("A"))) // {"role":"user","id":"A"}
println(mapper.readValue<Identity>("""{"role":"admin","id":"B"}""")) // Admin(id=B)
}
sealed class Result {
companion object : Polymorphic {
override val valueKey = "payload"
}
}
data class Success<T>(val value: T) : Result()
data class Failure(val message: String) : Result()
fun main() {
val mapper = jacksonObjectMapper().registerModule(PolymorphicModule())
println(mapper.writeValueAsString(Success(30))) // {"type":"Success","payload":{"value":30}}
println(mapper.readValue<Result>("""{"type":"Failure","payload":{"message":"Unknown"}}""")) // Failure(message=Unknown)
}
Representation as JSON string or number by supplied conversion rules.
data class Hexadecimal(val value: Int) {
companion object : Textual<Hexadecimal> {
override val Hexadecimal.text
get() = value.toString(16)
override fun fromText(value: String) =
Hexadecimal(value.toInt(16))
}
}
fun main() {
val mapper = ObjectMapper().registerModule(TextualModule())
println(mapper.writeValueAsString(Hexadecimal(1000))) // "3e8"
println(mapper.readValue<Hexadecimal>(""""2a"""")) // Hexadecimal(value=42)
}
Gradle Kotlin DSL
repositories {
mavenCentral()
maven("https://jitpack.io")
}
dependencies {
// Textual
implementation("io.github.justincase-jp.jackson-kotlin-commons", "textual", VERSION)
// Numerical
implementation("io.github.justincase-jp.jackson-kotlin-commons", "numerical", VERSION)
}
Currently the type parameter of Textual
/ Numerical
is not checked against its companion type,
so please be careful if you want to support a selected subset of possible values.