Slumber
A serialization framework built for Kotlin's type system. Nullable types, default values, sealed classes — handled without annotations.
Kotlin has a rich type system — serialization should use it
Kotlin distinguishes String from String? at the type level. Data classes have default
parameters.
Sealed classes define closed hierarchies. These are powerful features for modeling data correctly.
But most serialization frameworks predate Kotlin or target multiple languages — they don't see these
distinctions.
So you annotate, configure, and work around.
What Slumber does differently
You have a Kotlin data class. You want to serialize it to a Map (for a database, an API, a cache). Slumber uses Kotlin reflection to understand your types — nullable fields, default values, generics, sealed classes — and handles them without annotations or compiler plugins.
When deserialization fails, it tells you exactly which nested field caused it, with the full path.
The Solution
data class User(val name: String, val age: Int, val email: String? = null)
val codec = Codec.default
// Serialize ("slumber")
val map = codec.slumber(User("Alice", 30))
// → { "name": "Alice", "age": 30, "email": null }
// Deserialize ("awake")
val user = codec.awake<User>(mapOf("name" to "Bob", "age" to 25))
// → User(name="Bob", age=25, email=null) That's it. No annotations needed. No compiler plugin. Slumber uses Kotlin reflection to understand your data classes — nullable fields, default values, generics, and all.
What Makes It Different
Kotlin-First
Understands String vs String?, default parameters, data classes, sealed classes — at the type level.
Graceful Degradation
Nullable field receives bad data? Returns null instead of crashing. Required field fails? Detailed path in the error.
Two-Pass Error Handling
Fast pass first, no overhead. Only builds full diagnostic path on failure — performance when it works, clarity when it doesn't.
Format-Agnostic
Works with Maps and Lists, not JSON strings. Use it for databases, REST APIs, caches, or any storage backend.
Pluggable Modules
Custom type handling via SlumberModule. No annotation processors — just implement an interface.
Polymorphism Built-In
Sealed classes auto-detected. Custom discriminators, migration aliases, default fallback types — all supported.
The Naming
Slumber uses a playful metaphor:
- Slumber = serialize. Put your objects to sleep as raw data.
- Awake = deserialize. Wake your data back up as typed objects.
Quick Taste
Polymorphic sealed classes — zero configuration:
sealed class Event {
data class UserCreated(val userId: String) : Event()
data class UserDeleted(val userId: String, val reason: String?) : Event()
}
val codec = Codec.default
// Slumber a list of mixed types
val data = codec.slumber(listOf(
Event.UserCreated("alice"),
Event.UserDeleted("bob", reason = "inactive"),
))
// → [
// { "_type": "...UserCreated", "userId": "alice" },
// { "_type": "...UserDeleted", "userId": "bob", "reason": "inactive" }
// ]
// Awake it back — types are restored automatically
val events = codec.awake<List<Event>>(data)