0
# Serialization Modules
1
2
The SerializersModule system provides runtime configuration for custom serializers, contextual serialization, and polymorphic type handling. It allows you to register serializers that are resolved at runtime rather than compile time, enabling flexible serialization behavior for external types and polymorphic hierarchies.
3
4
## Capabilities
5
6
### Core Module Classes
7
8
The fundamental classes for building and managing serializers modules.
9
10
```kotlin { .api }
11
/**
12
* A collection of serializers used by ContextualSerializer and PolymorphicSerializer
13
* to override or provide serializers at runtime. Acts as a registry for runtime serializer resolution.
14
*/
15
sealed class SerializersModule {
16
/**
17
* Returns a contextual serializer associated with the given class.
18
* Used for types marked with @Contextual annotation.
19
*/
20
fun <T : Any> getContextual(
21
kClass: KClass<T>,
22
typeArgumentsSerializers: List<KSerializer<*>> = emptyList()
23
): KSerializer<T>?
24
25
/**
26
* Returns a polymorphic serializer for the given base class and actual value.
27
* Used for polymorphic serialization scenarios.
28
*/
29
fun getPolymorphic(
30
baseClass: KClass<Any>,
31
value: Any
32
): SerializationStrategy<Any>?
33
34
/**
35
* Returns a polymorphic deserializer for the given base class and class discriminator.
36
* Used during polymorphic deserialization.
37
*/
38
fun getPolymorphic(
39
baseClass: KClass<Any>,
40
serializedClassName: String?
41
): DeserializationStrategy<out Any>?
42
}
43
44
/**
45
* Builder class for creating SerializersModule using DSL syntax.
46
* Provides methods for registering contextual and polymorphic serializers.
47
*/
48
class SerializersModuleBuilder : SerializersModuleCollector {
49
/**
50
* Builds the final SerializersModule from registered serializers.
51
*/
52
fun build(): SerializersModule
53
}
54
55
/**
56
* Builder for registering polymorphic serializers within the scope of a base class.
57
* Provides type-safe registration of subclass serializers.
58
*/
59
class PolymorphicModuleBuilder<Base : Any> {
60
/**
61
* Register a subclass serializer for polymorphic serialization.
62
*/
63
fun <T : Base> subclass(kClass: KClass<T>, serializer: KSerializer<T>)
64
65
/**
66
* Register a subclass serializer using reified type parameter.
67
*/
68
inline fun <reified T : Base> subclass(serializer: KSerializer<T>)
69
70
/**
71
* Set a default serializer provider for unknown subclasses during serialization.
72
*/
73
fun defaultSerializer(defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?)
74
75
/**
76
* Set a default deserializer provider for unknown subclasses during deserialization.
77
*/
78
fun defaultDeserializer(defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?)
79
}
80
```
81
82
### Module Builder Functions
83
84
Factory functions for creating SerializersModule instances.
85
86
```kotlin { .api }
87
/**
88
* Creates a SerializersModule using DSL syntax.
89
* The primary way to build modules with multiple serializers.
90
* @param builderAction Lambda to configure the module
91
* @return Configured SerializersModule
92
*/
93
fun SerializersModule(builderAction: SerializersModuleBuilder.() -> Unit): SerializersModule
94
95
/**
96
* Creates a SerializersModule with a single contextual serializer.
97
* @param kClass The class to register a serializer for
98
* @param serializer The serializer to register
99
* @return SerializersModule containing the single registration
100
*/
101
fun <T : Any> serializersModuleOf(kClass: KClass<T>, serializer: KSerializer<T>): SerializersModule
102
103
/**
104
* Creates a SerializersModule with a single contextual serializer using reified type.
105
* @param serializer The serializer to register
106
* @return SerializersModule containing the single registration
107
*/
108
inline fun <reified T : Any> serializersModuleOf(serializer: KSerializer<T>): SerializersModule
109
110
/**
111
* Returns an empty SerializersModule that contains no serializers.
112
* @return Empty SerializersModule instance
113
*/
114
fun EmptySerializersModule(): SerializersModule
115
```
116
117
### Contextual Serialization
118
119
Methods for registering serializers that are resolved based on usage context.
120
121
```kotlin { .api }
122
/**
123
* Register a contextual serializer for the given class.
124
* Used for types that need custom serialization but aren't marked @Serializable.
125
* @param kClass The class to register a serializer for
126
* @param serializer The serializer to use for the class
127
*/
128
fun <T : Any> SerializersModuleBuilder.contextual(kClass: KClass<T>, serializer: KSerializer<T>)
129
130
/**
131
* Register a contextual serializer using reified type parameter.
132
* @param serializer The serializer to use for type T
133
*/
134
inline fun <reified T : Any> SerializersModuleBuilder.contextual(serializer: KSerializer<T>)
135
136
/**
137
* Register a contextual serializer provider for generic classes.
138
* The provider receives type argument serializers and returns a configured serializer.
139
* @param kClass The generic class to register a provider for
140
* @param provider Function that creates serializers based on type arguments
141
*/
142
fun <T : Any> SerializersModuleBuilder.contextual(
143
kClass: KClass<T>,
144
provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
145
)
146
147
/**
148
* Register a contextual serializer provider using reified type parameter.
149
* @param provider Function that creates serializers based on type arguments
150
*/
151
inline fun <reified T : Any> SerializersModuleBuilder.contextual(
152
provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
153
)
154
```
155
156
**Usage Examples:**
157
158
```kotlin
159
import kotlinx.serialization.*
160
import kotlinx.serialization.modules.*
161
import java.time.LocalDate
162
import java.util.UUID
163
164
// Custom serializers for external types
165
object LocalDateSerializer : KSerializer<LocalDate> {
166
override val descriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)
167
override fun serialize(encoder: Encoder, value: LocalDate) = encoder.encodeString(value.toString())
168
override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString())
169
}
170
171
object UUIDSerializer : KSerializer<UUID> {
172
override val descriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
173
override fun serialize(encoder: Encoder, value: UUID) = encoder.encodeString(value.toString())
174
override fun deserialize(decoder: Decoder): UUID = UUID.fromString(decoder.decodeString())
175
}
176
177
// Create module with contextual serializers
178
val module = SerializersModule {
179
contextual(LocalDate::class, LocalDateSerializer)
180
contextual(UUIDSerializer) // Reified version for UUID
181
182
// Generic contextual serializer
183
contextual(Box::class) { args ->
184
BoxSerializer(args[0]) // args[0] is the serializer for T in Box<T>
185
}
186
}
187
188
// Use with format
189
val json = Json { serializersModule = module }
190
191
@Serializable
192
data class Event(
193
@Contextual val id: UUID,
194
@Contextual val date: LocalDate,
195
val name: String
196
)
197
```
198
199
### Polymorphic Serialization
200
201
Methods for registering serializers for polymorphic type hierarchies.
202
203
```kotlin { .api }
204
/**
205
* Register a polymorphic serializer for a subclass of the base class.
206
* @param baseClass The polymorphic base class
207
* @param actualClass The concrete subclass
208
* @param actualSerializer The serializer for the subclass
209
*/
210
fun <Base : Any, Sub : Base> SerializersModuleBuilder.polymorphic(
211
baseClass: KClass<Base>,
212
actualClass: KClass<Sub>,
213
actualSerializer: KSerializer<Sub>
214
)
215
216
/**
217
* Configure polymorphic serialization for a base class using DSL.
218
* @param baseClass The polymorphic base class
219
* @param builderAction Lambda to configure subclass serializers
220
*/
221
fun <Base : Any> SerializersModuleBuilder.polymorphic(
222
baseClass: KClass<Base>,
223
builderAction: PolymorphicModuleBuilder<Base>.() -> Unit
224
)
225
226
/**
227
* Configure polymorphic serialization using reified type parameter.
228
* @param builderAction Lambda to configure subclass serializers
229
*/
230
inline fun <reified Base : Any> SerializersModuleBuilder.polymorphic(
231
builderAction: PolymorphicModuleBuilder<Base>.() -> Unit
232
)
233
234
/**
235
* Register a default serialization provider for unknown subclasses.
236
* @param baseClass The polymorphic base class
237
* @param defaultSerializerProvider Function to provide serializers for unknown types
238
*/
239
fun <Base : Any> SerializersModuleBuilder.polymorphicDefault(
240
baseClass: KClass<Base>,
241
defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?
242
)
243
244
/**
245
* Register a default deserialization provider for unknown subclasses.
246
* @param baseClass The polymorphic base class
247
* @param defaultDeserializerProvider Function to provide deserializers for unknown type names
248
*/
249
fun <Base : Any> SerializersModuleBuilder.polymorphicDefaultDeserializer(
250
baseClass: KClass<Base>,
251
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
252
)
253
```
254
255
**Usage Examples:**
256
257
```kotlin
258
import kotlinx.serialization.*
259
import kotlinx.serialization.modules.*
260
261
// Polymorphic base interface
262
@Serializable
263
sealed interface Animal {
264
val name: String
265
}
266
267
@Serializable
268
@SerialName("dog")
269
data class Dog(override val name: String, val breed: String) : Animal
270
271
@Serializable
272
@SerialName("cat")
273
data class Cat(override val name: String, val indoor: Boolean) : Animal
274
275
// Register polymorphic serializers
276
val animalModule = SerializersModule {
277
polymorphic(Animal::class) {
278
subclass(Dog::class, Dog.serializer())
279
subclass(Cat::class, Cat.serializer())
280
281
// Default serializer for unknown animals
282
defaultSerializer { animal ->
283
when (animal) {
284
is Dog -> Dog.serializer()
285
is Cat -> Cat.serializer()
286
else -> null
287
}
288
}
289
}
290
}
291
292
// External polymorphic hierarchy (not sealed)
293
abstract class Shape
294
data class Circle(val radius: Double) : Shape()
295
data class Rectangle(val width: Double, val height: Double) : Shape()
296
297
val shapeModule = SerializersModule {
298
polymorphic(Shape::class) {
299
subclass(Circle::class, CircleSerializer)
300
subclass(Rectangle::class, RectangleSerializer)
301
}
302
}
303
```
304
305
### Module Extension Functions
306
307
Functions for combining and manipulating SerializersModule instances.
308
309
```kotlin { .api }
310
/**
311
* Combines two SerializersModule instances, with the right module taking precedence.
312
* @param other The module to combine with this one
313
* @return Combined SerializersModule
314
*/
315
operator fun SerializersModule.plus(other: SerializersModule): SerializersModule
316
317
/**
318
* Combines two SerializersModule instances with explicit overwrite behavior.
319
* The right module overwrites registrations from the left module.
320
* @param other The module that will overwrite this one's registrations
321
* @return Combined SerializersModule with overwrite behavior
322
*/
323
fun SerializersModule.overwriteWith(other: SerializersModule): SerializersModule
324
```
325
326
**Usage Examples:**
327
328
```kotlin
329
val baseModule = SerializersModule {
330
contextual(UUID::class, UUIDSerializer)
331
}
332
333
val extendedModule = SerializersModule {
334
contextual(LocalDate::class, LocalDateSerializer)
335
polymorphic(Animal::class) {
336
subclass(Dog.serializer())
337
subclass(Cat.serializer())
338
}
339
}
340
341
// Combine modules
342
val combinedModule = baseModule + extendedModule
343
344
// Override with explicit behavior
345
val overrideModule = SerializersModule {
346
contextual(UUID::class, AlternativeUUIDSerializer)
347
}
348
val finalModule = baseModule.overwriteWith(overrideModule)
349
```
350
351
### Module Introspection
352
353
Interface for examining the contents of SerializersModule instances.
354
355
```kotlin { .api }
356
/**
357
* Interface that can introspect and accumulate the content of any SerializersModule.
358
* Used for copying or analyzing module configurations.
359
*/
360
interface SerializersModuleCollector {
361
/**
362
* Add a contextual serializer to the collection.
363
*/
364
fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>)
365
366
/**
367
* Add a contextual serializer provider to the collection.
368
*/
369
fun <T : Any> contextual(
370
kClass: KClass<T>,
371
provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
372
)
373
374
/**
375
* Add a polymorphic serializer to the collection.
376
*/
377
fun <Base : Any, Sub : Base> polymorphic(
378
baseClass: KClass<Base>,
379
actualClass: KClass<Sub>,
380
actualSerializer: KSerializer<Sub>
381
)
382
}
383
```
384
385
## Integration with Formats
386
387
SerializersModule is typically used when creating format instances:
388
389
```kotlin
390
import kotlinx.serialization.json.*
391
392
val customModule = SerializersModule {
393
contextual(LocalDate::class, LocalDateSerializer)
394
contextual(UUID::class, UUIDSerializer)
395
}
396
397
val json = Json {
398
serializersModule = customModule
399
// other format configuration
400
}
401
402
// All contextual types are now resolved using the module
403
val event = Event(UUID.randomUUID(), LocalDate.now(), "Conference")
404
val jsonString = json.encodeToString(event)
405
val decoded = json.decodeFromString<Event>(jsonString)
406
```
407
408
## Error Handling
409
410
Common errors when working with SerializersModule:
411
412
- **SerializationException**: Duplicate serializer registration for the same class
413
- **IllegalArgumentException**: Invalid module configurations or missing serializers
414
- **ClassCastException**: Type mismatches in polymorphic deserializer providers