Getting Started
Add the dependency, create a codec, serialize your first object.
1. Add the dependency
In your build.gradle.kts:
dependencies {
implementation("io.peekandpoke.ultra:slumber:0.107.2")
} Slumber requires Kotlin reflection (included transitively) and runs on the JVM.
2. Create a codec
import io.peekandpoke.ultra.slumber.Codec
// The default codec handles: primitives, data classes, enums, collections,
// sealed classes, java.time.*, kotlinx.datetime.*, and MpDateTime types.
val codec = Codec.default 3. Serialize (slumber)
data class Address(val city: String, val zip: String)
data class Person(val name: String, val age: Int, val address: Address)
val alice = Person("Alice", 30, Address("Berlin", "10115"))
val data = codec.slumber(alice)
// → {
// "name": "Alice",
// "age": 30,
// "address": { "city": "Berlin", "zip": "10115" }
// } The result is a Map<String, Any?> — not a JSON string. You can pass it to any storage backend, JSON encoder, or database driver.
4. Deserialize (awake)
import io.peekandpoke.ultra.slumber.awake
val input = mapOf(
"name" to "Bob",
"age" to 25,
"address" to mapOf("city" to "Munich", "zip" to "80331"),
)
val person = codec.awake<Person>(input)
// → Person(name="Bob", age=25, address=Address(city="Munich", zip="80331")) 5. Round-trip
val original = Person("Alice", 30, Address("Berlin", "10115"))
val restored = codec.awake<Person>(codec.slumber(original))
assert(restored == original) // true How it handles Kotlin features
Nullable fields
data class Profile(val name: String, val bio: String?)
// Missing nullable field → null
codec.awake<Profile>(mapOf("name" to "Alice"))
// → Profile(name="Alice", bio=null)
// Explicit null → null
codec.awake<Profile>(mapOf("name" to "Alice", "bio" to null))
// → Profile(name="Alice", bio=null)
// Invalid data on nullable field → null (graceful degradation)
codec.awake<Profile>(mapOf("name" to "Alice", "bio" to listOf(1, 2, 3)))
// → Profile(name="Alice", bio=null) Default parameters
data class Config(
val host: String = "localhost",
val port: Int = 8080,
val debug: Boolean = false,
)
// Missing fields use defaults
codec.awake<Config>(mapOf("debug" to true))
// → Config(host="localhost", port=8080, debug=true)
// Empty map → all defaults
codec.awake<Config>(emptyMap<String, Any>())
// → Config(host="localhost", port=8080, debug=false) Type coercion
data class Stats(val count: Int, val label: String)
// String "42" → Int 42, Number 100L → Int 100
codec.awake<Stats>(mapOf("count" to "42", "label" to 100))
// → Stats(count=42, label="100")
// Works for all numeric types: Int, Long, Double, Float, Short, Byte