Collections & Maps

Lists, sets, maps, and nested collections — all with full type awareness.

Lists and Sets

data class Team(
    val members: List<String>,
    val tags: Set<String>,
)

val codec = Codec.default

codec.slumber(Team(listOf("Alice", "Bob"), setOf("eng", "frontend")))
// → { "members": ["Alice", "Bob"], "tags": ["eng", "frontend"] }

codec.awake<Team>(mapOf(
    "members" to listOf("Alice", "Bob"),
    "tags" to listOf("eng", "frontend"),
))
// → Team(members=["Alice", "Bob"], tags={"eng", "frontend"})

Slumber supports List, MutableList, Set, MutableSet, and Iterable. Arrays are automatically converted to Lists on deserialization.

Typed collections

Inner types are fully preserved — a List<Int> will coerce string values to integers:

data class Scores(val values: List<Int>)

// String "42" is coerced to Int 42
codec.awake<Scores>(mapOf("values" to listOf("42", 100, 7)))
// → Scores(values=[42, 100, 7])

Collections of data classes

data class User(val name: String, val age: Int)
data class Directory(val users: List<User>)

codec.awake<Directory>(mapOf(
    "users" to listOf(
        mapOf("name" to "Alice", "age" to 30),
        mapOf("name" to "Bob", "age" to 25),
    )
))
// → Directory(users=[User("Alice", 30), User("Bob", 25)])

Maps

data class Config(val settings: Map<String, Int>)

codec.slumber(Config(mapOf("timeout" to 30, "retries" to 3)))
// → { "settings": { "timeout": 30, "retries": 3 } }

codec.awake<Config>(mapOf(
    "settings" to mapOf("timeout" to 30, "retries" to 3)
))
// → Config(settings={"timeout": 30, "retries": 3})

Both Map and MutableMap are supported. Key and value types are preserved through serialization.

Nullable elements

data class NullableItems(val items: List<String?>)

codec.awake<NullableItems>(mapOf(
    "items" to listOf("hello", null, "world")
))
// → NullableItems(items=["hello", null, "world"])

// Non-nullable List<String> with a null element → error
data class StrictItems(val items: List<String>)

codec.awake<StrictItems>(mapOf(
    "items" to listOf("hello", null)
))
// → AwakerException: "root.items.1 must not be null"

Nested collections

data class Matrix(val rows: List<List<Int>>)

codec.awake<Matrix>(mapOf(
    "rows" to listOf(
        listOf(1, 2, 3),
        listOf(4, 5, 6),
    )
))
// → Matrix(rows=[[1, 2, 3], [4, 5, 6]])