0
# Serializers Module
1
2
The serializers module system provides runtime resolution of contextual and polymorphic serializers, enabling flexible serialization strategies that can be configured at runtime rather than compile time.
3
4
## Core Module Classes
5
6
### SerializersModule
7
8
Container for contextual and polymorphic serializers that can be queried at runtime.
9
10
```kotlin { .api }
11
sealed class SerializersModule {
12
@ExperimentalSerializationApi
13
abstract fun <T : Any> getContextual(
14
kClass: KClass<T>,
15
typeArgumentsSerializers: List<KSerializer<*>> = emptyList()
16
): KSerializer<T>?
17
18
@ExperimentalSerializationApi
19
abstract fun <T : Any> getPolymorphic(
20
baseClass: KClass<in T>,
21
value: T
22
): SerializationStrategy<T>?
23
24
@ExperimentalSerializationApi
25
abstract fun <T : Any> getPolymorphic(
26
baseClass: KClass<in T>,
27
serializedClassName: String?
28
): DeserializationStrategy<T>?
29
30
@ExperimentalSerializationApi
31
abstract fun dumpTo(collector: SerializersModuleCollector)
32
}
33
```
34
35
### SerializersModuleCollector
36
37
Base interface for collecting serializer registrations.
38
39
```kotlin { .api }
40
@ExperimentalSerializationApi
41
interface SerializersModuleCollector {
42
fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>)
43
fun <T : Any> contextual(
44
kClass: KClass<T>,
45
provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
46
)
47
fun <Base : Any, Sub : Base> polymorphic(
48
baseClass: KClass<Base>,
49
actualClass: KClass<Sub>,
50
actualSerializer: KSerializer<Sub>
51
)
52
fun <Base : Any> polymorphicDefaultSerializer(
53
baseClass: KClass<Base>,
54
defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?
55
)
56
fun <Base : Any> polymorphicDefaultDeserializer(
57
baseClass: KClass<Base>,
58
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
59
)
60
}
61
```
62
63
### SerializersModuleBuilder
64
65
Builder for constructing SerializersModule instances.
66
67
```kotlin { .api }
68
class SerializersModuleBuilder : SerializersModuleCollector {
69
// Overrides from SerializersModuleCollector (inherited methods)
70
override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>)
71
override fun <T : Any> contextual(
72
kClass: KClass<T>,
73
provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
74
)
75
override fun <Base : Any, Sub : Base> polymorphic(
76
baseClass: KClass<Base>,
77
actualClass: KClass<Sub>,
78
actualSerializer: KSerializer<Sub>
79
)
80
override fun <Base : Any> polymorphicDefaultSerializer(
81
baseClass: KClass<Base>,
82
defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?
83
)
84
override fun <Base : Any> polymorphicDefaultDeserializer(
85
baseClass: KClass<Base>,
86
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
87
)
88
89
// Additional methods specific to builder
90
fun include(module: SerializersModule)
91
}
92
```
93
94
## Module Building Functions
95
96
### SerializersModule Constructor
97
98
Creates a new SerializersModule using a builder pattern.
99
100
```kotlin { .api }
101
fun SerializersModule(builderAction: SerializersModuleBuilder.() -> Unit): SerializersModule
102
```
103
104
### Factory Functions
105
106
```kotlin { .api }
107
fun EmptySerializersModule(): SerializersModule
108
109
@Deprecated("Replaced with EmptySerializersModule()")
110
val EmptySerializersModule: SerializersModule
111
112
operator fun SerializersModule.plus(other: SerializersModule): SerializersModule
113
114
infix fun SerializersModule.overwriteWith(other: SerializersModule): SerializersModule
115
116
fun <T : Any> serializersModuleOf(
117
kClass: KClass<T>,
118
serializer: KSerializer<T>
119
): SerializersModule
120
121
inline fun <reified T : Any> serializersModuleOf(
122
serializer: KSerializer<T>
123
): SerializersModule
124
```
125
126
## Polymorphic Module Builder
127
128
### PolymorphicModuleBuilder
129
130
Specialized builder for configuring polymorphic serialization within a specific base class.
131
132
```kotlin { .api }
133
class PolymorphicModuleBuilder<Base : Any> {
134
fun <Sub : Base> subclass(clazz: KClass<Sub>, serializer: KSerializer<Sub>)
135
inline fun <reified Sub : Base> subclass(serializer: KSerializer<Sub>)
136
137
fun default(defaultSerializerProvider: (value: Base?) -> SerializationStrategy<Base>?)
138
fun defaultDeserializer(
139
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
140
)
141
}
142
```
143
144
**Extension Functions:**
145
```kotlin { .api }
146
inline fun <reified T : Any> SerializersModuleBuilder.contextual(serializer: KSerializer<T>)
147
148
inline fun <Base : Any> SerializersModuleBuilder.polymorphic(
149
baseClass: KClass<Base>,
150
baseSerializer: KSerializer<Base>? = null,
151
builderAction: PolymorphicModuleBuilder<Base>.() -> Unit
152
)
153
```
154
155
## Usage Examples
156
157
### Basic Module Creation
158
159
```kotlin
160
val module = SerializersModule {
161
// Register contextual serializers
162
contextual(LocalDateTime::class, LocalDateTimeSerializer)
163
contextual<BigDecimal>(BigDecimalSerializer)
164
165
// Register polymorphic serializers
166
polymorphic(Animal::class) {
167
subclass(Dog::class, Dog.serializer())
168
subclass(Cat::class, Cat.serializer())
169
}
170
}
171
```
172
173
### Contextual Serialization
174
175
```kotlin
176
// Define a contextual serializer for external types
177
object LocalDateTimeSerializer : KSerializer<LocalDateTime> {
178
override val descriptor = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)
179
180
override fun serialize(encoder: Encoder, value: LocalDateTime) {
181
encoder.encodeString(value.toString())
182
}
183
184
override fun deserialize(decoder: Decoder): LocalDateTime {
185
return LocalDateTime.parse(decoder.decodeString())
186
}
187
}
188
189
// Register the contextual serializer
190
val module = SerializersModule {
191
contextual(LocalDateTime::class, LocalDateTimeSerializer)
192
}
193
194
// Use with @Contextual annotation
195
@Serializable
196
data class Event(
197
val name: String,
198
@Contextual
199
val timestamp: LocalDateTime
200
)
201
```
202
203
### Polymorphic Serialization
204
205
```kotlin
206
@Serializable
207
sealed class Animal {
208
abstract val name: String
209
}
210
211
@Serializable
212
@SerialName("dog")
213
data class Dog(override val name: String, val breed: String) : Animal()
214
215
@Serializable
216
@SerialName("cat")
217
data class Cat(override val name: String, val isIndoor: Boolean) : Animal()
218
219
// Configure polymorphic module
220
val module = SerializersModule {
221
polymorphic(Animal::class) {
222
subclass(Dog::class, Dog.serializer())
223
subclass(Cat::class, Cat.serializer())
224
}
225
}
226
227
// Usage with polymorphic property
228
@Serializable
229
data class Owner(
230
val name: String,
231
@Polymorphic
232
val pet: Animal
233
)
234
```
235
236
### Advanced Polymorphic Configuration
237
238
```kotlin
239
sealed class Shape
240
241
@Serializable
242
@SerialName("circle")
243
data class Circle(val radius: Double) : Shape()
244
245
@Serializable
246
@SerialName("rectangle")
247
data class Rectangle(val width: Double, val height: Double) : Shape()
248
249
val module = SerializersModule {
250
polymorphic(Shape::class) {
251
subclass(Circle::class, Circle.serializer())
252
subclass(Rectangle::class, Rectangle.serializer())
253
254
// Default serializer for unknown types during serialization
255
default { value ->
256
when (value) {
257
is Circle -> Circle.serializer()
258
is Rectangle -> Rectangle.serializer()
259
else -> null
260
}
261
}
262
263
// Default deserializer for unknown class names during deserialization
264
defaultDeserializer { className ->
265
when (className) {
266
"legacy_circle" -> Circle.serializer()
267
"legacy_rect" -> Rectangle.serializer()
268
else -> null
269
}
270
}
271
}
272
}
273
```
274
275
### Generic Type Contextual Serializers
276
277
```kotlin
278
// Custom serializer for generic types
279
class ListAsStringSerializer<T>(
280
private val elementSerializer: KSerializer<T>
281
) : KSerializer<List<T>> {
282
override val descriptor = PrimitiveSerialDescriptor("ListAsString", PrimitiveKind.STRING)
283
284
override fun serialize(encoder: Encoder, value: List<T>) {
285
val json = value.joinToString(",") { element ->
286
Json.encodeToString(elementSerializer, element)
287
}
288
encoder.encodeString("[$json]")
289
}
290
291
override fun deserialize(decoder: Decoder): List<T> {
292
val jsonString = decoder.decodeString()
293
// Parse and deserialize elements...
294
TODO("Implement parsing logic")
295
}
296
}
297
298
// Register with type parameter support
299
val module = SerializersModule {
300
contextual(List::class) { typeArgs ->
301
@Suppress("UNCHECKED_CAST")
302
ListAsStringSerializer(typeArgs[0] as KSerializer<Any>)
303
}
304
}
305
```
306
307
### Module Composition
308
309
```kotlin
310
val baseModule = SerializersModule {
311
contextual(UUID::class, UUIDSerializer)
312
contextual(LocalDate::class, LocalDateSerializer)
313
}
314
315
val extendedModule = SerializersModule {
316
include(baseModule)
317
318
contextual(ZonedDateTime::class, ZonedDateTimeSerializer)
319
320
polymorphic(Event::class) {
321
subclass(UserEvent::class, UserEvent.serializer())
322
subclass(SystemEvent::class, SystemEvent.serializer())
323
}
324
}
325
326
// Combine modules using plus operator
327
val combinedModule = baseModule + extendedModule
328
```
329
330
### Runtime Serializer Resolution
331
332
```kotlin
333
val module = SerializersModule {
334
contextual(BigInteger::class, BigIntegerSerializer)
335
polymorphic(Animal::class) {
336
subclass(Dog::class, Dog.serializer())
337
subclass(Cat::class, Cat.serializer())
338
}
339
}
340
341
// Query contextual serializers
342
val bigIntSerializer = module.getContextual(BigInteger::class)
343
println("Found contextual serializer: ${bigIntSerializer != null}")
344
345
// Query polymorphic serializers
346
val dogInstance = Dog("Buddy", "Golden Retriever")
347
val dogSerializer = module.getPolymorphic(Animal::class, dogInstance)
348
println("Found polymorphic serializer: ${dogSerializer != null}")
349
350
// Query by class name for deserialization
351
val catDeserializer = module.getPolymorphic(Animal::class, "cat")
352
println("Found deserializer for 'cat': ${catDeserializer != null}")
353
```
354
355
### Integration with Formats
356
357
```kotlin
358
val module = SerializersModule {
359
contextual(LocalDateTime::class, LocalDateTimeSerializer)
360
polymorphic(Shape::class) {
361
subclass(Circle::class, Circle.serializer())
362
subclass(Rectangle::class, Rectangle.serializer())
363
}
364
}
365
366
// Use with JSON format (requires kotlinx-serialization-json)
367
val json = Json {
368
serializersModule = module
369
// Other JSON configuration...
370
}
371
372
@Serializable
373
data class Drawing(
374
val title: String,
375
@Contextual
376
val createdAt: LocalDateTime,
377
@Polymorphic
378
val shapes: List<Shape>
379
)
380
381
val drawing = Drawing(
382
title = "My Drawing",
383
createdAt = LocalDateTime.now(),
384
shapes = listOf(
385
Circle(5.0),
386
Rectangle(10.0, 20.0)
387
)
388
)
389
390
val jsonString = json.encodeToString(drawing)
391
val decoded = json.decodeFromString<Drawing>(jsonString)
392
```
393
394
## Best Practices
395
396
1. **Module Scope**: Create modules at application startup and reuse them
397
2. **Composition**: Use `include()` and `+` operator to compose modules from smaller, focused modules
398
3. **Default Providers**: Use default serializer/deserializer providers for handling unknown types gracefully
399
4. **Type Safety**: Prefer sealed classes for polymorphic hierarchies when possible
400
5. **Performance**: Cache module lookups in performance-critical code paths