0
# Core Serializers
1
2
Complete reference for the KSerializer interface and core serialization strategies in kotlinx.serialization-core-js.
3
4
## Core Interfaces
5
6
### KSerializer<T>
7
8
The primary interface that combines serialization and deserialization capabilities.
9
10
```kotlin
11
interface KSerializer<T> : SerializationStrategy<T>, DeserializationStrategy<T> {
12
val descriptor: SerialDescriptor
13
}
14
```
15
{ .api }
16
17
**Usage:**
18
19
```javascript
20
// Get serializer for a class
21
const userSerializer = User.serializer();
22
23
// Use with any format
24
const json = format.encodeToString(userSerializer, user);
25
const decoded = format.decodeFromString(userSerializer, json);
26
27
// Access descriptor
28
console.log(userSerializer.descriptor.serialName); // "User"
29
```
30
31
### SerializationStrategy<T>
32
33
Interface for types that can be serialized to a format.
34
35
```kotlin
36
interface SerializationStrategy<T> {
37
val descriptor: SerialDescriptor
38
fun serialize(encoder: Encoder, value: T)
39
}
40
```
41
{ .api }
42
43
**Usage:**
44
45
```javascript
46
class CustomSerializationStrategy {
47
constructor(descriptor) {
48
this.descriptor = descriptor;
49
}
50
51
serialize(encoder, value) {
52
// Custom serialization logic
53
encoder.encodeString(value.toString());
54
}
55
}
56
```
57
58
### DeserializationStrategy<T>
59
60
Interface for types that can be deserialized from a format.
61
62
```kotlin
63
interface DeserializationStrategy<T> {
64
val descriptor: SerialDescriptor
65
fun deserialize(decoder: Decoder): T
66
}
67
```
68
{ .api }
69
70
**Usage:**
71
72
```javascript
73
class CustomDeserializationStrategy {
74
constructor(descriptor) {
75
this.descriptor = descriptor;
76
}
77
78
deserialize(decoder) {
79
// Custom deserialization logic
80
const str = decoder.decodeString();
81
return parseCustomFormat(str);
82
}
83
}
84
```
85
86
## Serializer Factory Functions
87
88
### serializer<T>()
89
90
Retrieves a serializer for a reified type T.
91
92
```kotlin
93
inline fun <reified T> serializer(): KSerializer<T>
94
```
95
{ .api }
96
97
**Usage:**
98
99
```javascript
100
// For basic types
101
const stringSerializer = serializer<String>();
102
const intSerializer = serializer<Int>();
103
104
// For collections with type parameters
105
const listSerializer = serializer<List<String>>();
106
const mapSerializer = serializer<Map<String, Int>>();
107
108
// For custom classes
109
const userSerializer = serializer<User>();
110
```
111
112
### SerializersModule.serializer<T>()
113
114
Retrieves a serializer with contextual lookup from a module.
115
116
```kotlin
117
inline fun <reified T> SerializersModule.serializer(): KSerializer<T>
118
```
119
{ .api }
120
121
**Usage:**
122
123
```javascript
124
const module = SerializersModule {
125
contextual(Date, CustomDateSerializer)
126
};
127
128
// Gets contextual serializer if available, otherwise default
129
const dateSerializer = module.serializer<Date>();
130
```
131
132
### serializer(type: KType)
133
134
Creates a serializer for a given KType (includes nullability and generics).
135
136
```kotlin
137
fun serializer(type: KType): KSerializer<Any?>
138
```
139
{ .api }
140
141
**Usage:**
142
143
```javascript
144
import { typeOf } from 'kotlin-stdlib-js';
145
146
// For nullable types
147
const nullableStringType = typeOf<String?>();
148
const nullableStringSerializer = serializer(nullableStringType);
149
150
// For generic types
151
const listOfStringType = typeOf<List<String>>();
152
const listSerializer = serializer(listOfStringType);
153
```
154
155
### serializer(kClass, typeArgs, isNullable)
156
157
Creates a serializer for a KClass with type arguments (Experimental).
158
159
```kotlin
160
@ExperimentalSerializationApi
161
fun serializer(
162
kClass: KClass<*>,
163
typeArgumentsSerializers: Array<KSerializer<*>>,
164
isNullable: Boolean
165
): KSerializer<Any?>
166
```
167
{ .api }
168
169
**Usage:**
170
171
```javascript
172
// Create List<User> serializer
173
const userClass = User::class;
174
const userSerializer = serializer<User>();
175
const listUserSerializer = serializer(
176
List::class,
177
[userSerializer],
178
false // not nullable
179
);
180
```
181
182
### serializerOrNull(type: KType)
183
184
Creates a serializer for KType or returns null if unavailable.
185
186
```kotlin
187
fun serializerOrNull(type: KType): KSerializer<Any?>?
188
```
189
{ .api }
190
191
**Usage:**
192
193
```javascript
194
const type = typeOf<SomeUnknownClass>();
195
const serializer = serializerOrNull(type);
196
197
if (serializer !== null) {
198
// Safe to use serializer
199
const json = format.encodeToString(serializer, value);
200
} else {
201
console.log("No serializer available for type");
202
}
203
```
204
205
## Special Serializers
206
207
### ContextualSerializer<T>
208
209
Serializer that delegates to runtime lookup in SerializersModule (Experimental).
210
211
```kotlin
212
@ExperimentalSerializationApi
213
class ContextualSerializer<T : Any>(
214
private val serializableClass: KClass<T>,
215
private val fallbackSerializer: KSerializer<T>? = null,
216
private val typeArgumentsSerializers: Array<KSerializer<*>> = emptyArray()
217
) : KSerializer<T>
218
```
219
{ .api }
220
221
**Usage:**
222
223
```javascript
224
// Create contextual serializer for Date
225
const dateContextualSerializer = new ContextualSerializer(
226
Date::class,
227
DefaultDateSerializer, // fallback
228
[] // no type arguments
229
);
230
231
// Use in SerializersModule
232
const module = SerializersModule {
233
contextual(Date::class, CustomDateSerializer)
234
};
235
236
// When used with module, CustomDateSerializer will be used
237
// When used without module, DefaultDateSerializer will be used
238
```
239
240
### PolymorphicSerializer<T>
241
242
Serializer for polymorphic serialization of class hierarchies.
243
244
```kotlin
245
class PolymorphicSerializer<T : Any>(private val baseClass: KClass<T>) : KSerializer<T>
246
```
247
{ .api }
248
249
**Usage:**
250
251
```javascript
252
// Create polymorphic serializer for base class
253
const shapeSerializer = new PolymorphicSerializer(Shape::class);
254
255
// Configure subclasses in module
256
const module = SerializersModule {
257
polymorphic(Shape::class) {
258
subclass(Circle::class)
259
subclass(Rectangle::class)
260
subclass(Triangle::class)
261
}
262
};
263
264
// Use with format configured with the module
265
const json = format.encodeToString(shapeSerializer, circleInstance);
266
// Output includes type discriminator: {"type":"Circle","radius":5}
267
```
268
269
### SealedClassSerializer<T>
270
271
Internal serializer for sealed classes (handled automatically).
272
273
```kotlin
274
@InternalSerializationApi
275
class SealedClassSerializer<T : Any>(
276
private val serialName: String,
277
private val baseClass: KClass<T>,
278
private val subclassSerializers: Array<KSerializer<out T>>,
279
private val subclassNames: Array<String>
280
) : KSerializer<T>
281
```
282
{ .api }
283
284
**Usage:**
285
286
```javascript
287
// Sealed class (automatically gets SealedClassSerializer)
288
@Serializable
289
sealed class Result {
290
@Serializable
291
static class Success extends Result {
292
constructor(data) {
293
super();
294
this.data = data;
295
}
296
}
297
298
@Serializable
299
static class Error extends Result {
300
constructor(message) {
301
super();
302
this.message = message;
303
}
304
}
305
}
306
307
// Automatically uses SealedClassSerializer
308
const resultSerializer = Result.serializer();
309
```
310
311
## Companion Object Serializers
312
313
Many standard types provide serializers through companion objects:
314
315
### Primitive Type Serializers
316
317
```kotlin
318
// Companion object extensions
319
val Char.Companion.serializer: KSerializer<Char>
320
val Byte.Companion.serializer: KSerializer<Byte>
321
val Short.Companion.serializer: KSerializer<Short>
322
val Int.Companion.serializer: KSerializer<Int>
323
val Long.Companion.serializer: KSerializer<Long>
324
val Float.Companion.serializer: KSerializer<Float>
325
val Double.Companion.serializer: KSerializer<Double>
326
val Boolean.Companion.serializer: KSerializer<Boolean>
327
val String.Companion.serializer: KSerializer<String>
328
```
329
{ .api }
330
331
**Usage:**
332
333
```javascript
334
// Access via companion objects
335
const charSer = Char.serializer();
336
const byteSer = Byte.serializer();
337
const shortSer = Short.serializer();
338
const intSer = Int.serializer();
339
const longSer = Long.serializer();
340
const floatSer = Float.serializer();
341
const doubleSer = Double.serializer();
342
const booleanSer = Boolean.serializer();
343
const stringSer = String.serializer();
344
```
345
346
### Special Type Serializers
347
348
```kotlin
349
val Unit.serializer: KSerializer<Unit>
350
val UInt.Companion.serializer: KSerializer<UInt>
351
val ULong.Companion.serializer: KSerializer<ULong>
352
val UByte.Companion.serializer: KSerializer<UByte>
353
val UShort.Companion.serializer: KSerializer<UShort>
354
val Duration.Companion.serializer: KSerializer<Duration>
355
```
356
{ .api }
357
358
**Usage:**
359
360
```javascript
361
const unitSer = Unit.serializer();
362
const uintSer = UInt.serializer();
363
const ulongSer = ULong.serializer();
364
const ubyteSer = UByte.serializer();
365
const ushortSer = UShort.serializer();
366
const durationSer = Duration.serializer();
367
```
368
369
### Experimental Serializers
370
371
```kotlin
372
@ExperimentalSerializationApi
373
val Instant.Companion.serializer: KSerializer<Instant>
374
375
@ExperimentalSerializationApi
376
val Uuid.Companion.serializer: KSerializer<Uuid>
377
```
378
{ .api }
379
380
**Usage:**
381
382
```javascript
383
// Experimental APIs (may change)
384
const instantSer = Instant.serializer();
385
const uuidSer = Uuid.serializer();
386
```
387
388
## Nullable Serializers
389
390
### .nullable Property
391
392
All serializers can be made nullable using the `.nullable` property:
393
394
```kotlin
395
val KSerializer<T>.nullable: KSerializer<T?>
396
```
397
{ .api }
398
399
**Usage:**
400
401
```javascript
402
// Make any serializer nullable
403
const stringSerializer = String.serializer();
404
const nullableStringSerializer = stringSerializer.nullable;
405
406
// Works with complex types too
407
const userSerializer = User.serializer();
408
const nullableUserSerializer = userSerializer.nullable;
409
410
// Use with collections
411
const listSerializer = ListSerializer(String.serializer());
412
const nullableListSerializer = listSerializer.nullable;
413
```
414
415
## Custom Serializer Implementation
416
417
### Basic Custom Serializer
418
419
```javascript
420
class CustomUserSerializer {
421
constructor() {
422
this.descriptor = buildClassSerialDescriptor("CustomUser") {
423
element("fullName", String.serializer().descriptor)
424
element("birthYear", Int.serializer().descriptor)
425
};
426
}
427
428
serialize(encoder, value) {
429
const composite = encoder.beginStructure(this.descriptor);
430
composite.encodeStringElement(this.descriptor, 0, `${value.firstName} ${value.lastName}`);
431
composite.encodeIntElement(this.descriptor, 1, new Date().getFullYear() - value.age);
432
composite.endStructure(this.descriptor);
433
}
434
435
deserialize(decoder) {
436
const composite = decoder.beginStructure(this.descriptor);
437
438
let fullName = "";
439
let birthYear = 0;
440
441
while (true) {
442
const index = composite.decodeElementIndex(this.descriptor);
443
if (index === CompositeDecoder.DECODE_DONE) break;
444
445
switch (index) {
446
case 0:
447
fullName = composite.decodeStringElement(this.descriptor, 0);
448
break;
449
case 1:
450
birthYear = composite.decodeIntElement(this.descriptor, 1);
451
break;
452
default:
453
throw new SerializationException(`Unexpected index: ${index}`);
454
}
455
}
456
457
composite.endStructure(this.descriptor);
458
459
const parts = fullName.split(' ');
460
const age = new Date().getFullYear() - birthYear;
461
return new User(parts[0], parts[1], age);
462
}
463
}
464
```
465
466
### Using Custom Serializers
467
468
```javascript
469
// Register with @Serializable
470
@Serializable(CustomUserSerializer::class)
471
class User {
472
constructor(firstName, lastName, age) {
473
this.firstName = firstName;
474
this.lastName = lastName;
475
this.age = age;
476
}
477
}
478
479
// Or use directly
480
const customSerializer = new CustomUserSerializer();
481
const json = format.encodeToString(customSerializer, user);
482
const decoded = format.decodeFromString(customSerializer, json);
483
```
484
485
## Error Handling
486
487
Serializers can throw specific exceptions:
488
489
```javascript
490
class ValidatingSerializer {
491
serialize(encoder, value) {
492
if (!this.isValid(value)) {
493
throw new SerializationException("Invalid value for serialization");
494
}
495
// ... serialization logic
496
}
497
498
deserialize(decoder) {
499
const result = /* ... deserialization logic */;
500
501
if (!this.isValid(result)) {
502
throw new SerializationException("Deserialized value failed validation");
503
}
504
505
return result;
506
}
507
508
isValid(value) {
509
// Validation logic
510
return value !== null && value !== undefined;
511
}
512
}
513
```
514
515
## TypeScript Integration
516
517
Serializers maintain full type safety in TypeScript:
518
519
```typescript
520
// Typed serializer creation
521
const userSerializer: KSerializer<User> = User.serializer();
522
const listSerializer: KSerializer<Array<User>> = ListSerializer(userSerializer);
523
524
// Generic serializer functions
525
function serializeList<T>(serializer: KSerializer<T>, items: T[]): string {
526
const listSer = ListSerializer(serializer);
527
return format.encodeToString(listSer, items);
528
}
529
530
// Type-safe usage
531
const users: User[] = [new User("John", 30), new User("Jane", 25)];
532
const json: string = serializeList(User.serializer(), users);
533
```
534
535
The serializer system provides the foundation for all serialization operations while maintaining type safety and performance across different formats and use cases.