Kotlin multiplatform reflectionless serialization library core module for JavaScript platform
—
Complete reference for the KSerializer interface and core serialization strategies in kotlinx.serialization-core-js.
The primary interface that combines serialization and deserialization capabilities.
interface KSerializer<T> : SerializationStrategy<T>, DeserializationStrategy<T> {
val descriptor: SerialDescriptor
}{ .api }
Usage:
// Get serializer for a class
const userSerializer = User.serializer();
// Use with any format
const json = format.encodeToString(userSerializer, user);
const decoded = format.decodeFromString(userSerializer, json);
// Access descriptor
console.log(userSerializer.descriptor.serialName); // "User"Interface for types that can be serialized to a format.
interface SerializationStrategy<T> {
val descriptor: SerialDescriptor
fun serialize(encoder: Encoder, value: T)
}{ .api }
Usage:
class CustomSerializationStrategy {
constructor(descriptor) {
this.descriptor = descriptor;
}
serialize(encoder, value) {
// Custom serialization logic
encoder.encodeString(value.toString());
}
}Interface for types that can be deserialized from a format.
interface DeserializationStrategy<T> {
val descriptor: SerialDescriptor
fun deserialize(decoder: Decoder): T
}{ .api }
Usage:
class CustomDeserializationStrategy {
constructor(descriptor) {
this.descriptor = descriptor;
}
deserialize(decoder) {
// Custom deserialization logic
const str = decoder.decodeString();
return parseCustomFormat(str);
}
}Retrieves a serializer for a reified type T.
inline fun <reified T> serializer(): KSerializer<T>{ .api }
Usage:
// For basic types
const stringSerializer = serializer<String>();
const intSerializer = serializer<Int>();
// For collections with type parameters
const listSerializer = serializer<List<String>>();
const mapSerializer = serializer<Map<String, Int>>();
// For custom classes
const userSerializer = serializer<User>();Retrieves a serializer with contextual lookup from a module.
inline fun <reified T> SerializersModule.serializer(): KSerializer<T>{ .api }
Usage:
const module = SerializersModule {
contextual(Date, CustomDateSerializer)
};
// Gets contextual serializer if available, otherwise default
const dateSerializer = module.serializer<Date>();Creates a serializer for a given KType (includes nullability and generics).
fun serializer(type: KType): KSerializer<Any?>{ .api }
Usage:
import { typeOf } from 'kotlin-stdlib-js';
// For nullable types
const nullableStringType = typeOf<String?>();
const nullableStringSerializer = serializer(nullableStringType);
// For generic types
const listOfStringType = typeOf<List<String>>();
const listSerializer = serializer(listOfStringType);Creates a serializer for a KClass with type arguments (Experimental).
@ExperimentalSerializationApi
fun serializer(
kClass: KClass<*>,
typeArgumentsSerializers: Array<KSerializer<*>>,
isNullable: Boolean
): KSerializer<Any?>{ .api }
Usage:
// Create List<User> serializer
const userClass = User::class;
const userSerializer = serializer<User>();
const listUserSerializer = serializer(
List::class,
[userSerializer],
false // not nullable
);Creates a serializer for KType or returns null if unavailable.
fun serializerOrNull(type: KType): KSerializer<Any?>?{ .api }
Usage:
const type = typeOf<SomeUnknownClass>();
const serializer = serializerOrNull(type);
if (serializer !== null) {
// Safe to use serializer
const json = format.encodeToString(serializer, value);
} else {
console.log("No serializer available for type");
}Serializer that delegates to runtime lookup in SerializersModule (Experimental).
@ExperimentalSerializationApi
class ContextualSerializer<T : Any>(
private val serializableClass: KClass<T>,
private val fallbackSerializer: KSerializer<T>? = null,
private val typeArgumentsSerializers: Array<KSerializer<*>> = emptyArray()
) : KSerializer<T>{ .api }
Usage:
// Create contextual serializer for Date
const dateContextualSerializer = new ContextualSerializer(
Date::class,
DefaultDateSerializer, // fallback
[] // no type arguments
);
// Use in SerializersModule
const module = SerializersModule {
contextual(Date::class, CustomDateSerializer)
};
// When used with module, CustomDateSerializer will be used
// When used without module, DefaultDateSerializer will be usedSerializer for polymorphic serialization of class hierarchies.
class PolymorphicSerializer<T : Any>(private val baseClass: KClass<T>) : KSerializer<T>{ .api }
Usage:
// Create polymorphic serializer for base class
const shapeSerializer = new PolymorphicSerializer(Shape::class);
// Configure subclasses in module
const module = SerializersModule {
polymorphic(Shape::class) {
subclass(Circle::class)
subclass(Rectangle::class)
subclass(Triangle::class)
}
};
// Use with format configured with the module
const json = format.encodeToString(shapeSerializer, circleInstance);
// Output includes type discriminator: {"type":"Circle","radius":5}Internal serializer for sealed classes (handled automatically).
@InternalSerializationApi
class SealedClassSerializer<T : Any>(
private val serialName: String,
private val baseClass: KClass<T>,
private val subclassSerializers: Array<KSerializer<out T>>,
private val subclassNames: Array<String>
) : KSerializer<T>{ .api }
Usage:
// Sealed class (automatically gets SealedClassSerializer)
@Serializable
sealed class Result {
@Serializable
static class Success extends Result {
constructor(data) {
super();
this.data = data;
}
}
@Serializable
static class Error extends Result {
constructor(message) {
super();
this.message = message;
}
}
}
// Automatically uses SealedClassSerializer
const resultSerializer = Result.serializer();Many standard types provide serializers through companion objects:
// Companion object extensions
val Char.Companion.serializer: KSerializer<Char>
val Byte.Companion.serializer: KSerializer<Byte>
val Short.Companion.serializer: KSerializer<Short>
val Int.Companion.serializer: KSerializer<Int>
val Long.Companion.serializer: KSerializer<Long>
val Float.Companion.serializer: KSerializer<Float>
val Double.Companion.serializer: KSerializer<Double>
val Boolean.Companion.serializer: KSerializer<Boolean>
val String.Companion.serializer: KSerializer<String>{ .api }
Usage:
// Access via companion objects
const charSer = Char.serializer();
const byteSer = Byte.serializer();
const shortSer = Short.serializer();
const intSer = Int.serializer();
const longSer = Long.serializer();
const floatSer = Float.serializer();
const doubleSer = Double.serializer();
const booleanSer = Boolean.serializer();
const stringSer = String.serializer();val Unit.serializer: KSerializer<Unit>
val UInt.Companion.serializer: KSerializer<UInt>
val ULong.Companion.serializer: KSerializer<ULong>
val UByte.Companion.serializer: KSerializer<UByte>
val UShort.Companion.serializer: KSerializer<UShort>
val Duration.Companion.serializer: KSerializer<Duration>{ .api }
Usage:
const unitSer = Unit.serializer();
const uintSer = UInt.serializer();
const ulongSer = ULong.serializer();
const ubyteSer = UByte.serializer();
const ushortSer = UShort.serializer();
const durationSer = Duration.serializer();@ExperimentalSerializationApi
val Instant.Companion.serializer: KSerializer<Instant>
@ExperimentalSerializationApi
val Uuid.Companion.serializer: KSerializer<Uuid>{ .api }
Usage:
// Experimental APIs (may change)
const instantSer = Instant.serializer();
const uuidSer = Uuid.serializer();All serializers can be made nullable using the .nullable property:
val KSerializer<T>.nullable: KSerializer<T?>{ .api }
Usage:
// Make any serializer nullable
const stringSerializer = String.serializer();
const nullableStringSerializer = stringSerializer.nullable;
// Works with complex types too
const userSerializer = User.serializer();
const nullableUserSerializer = userSerializer.nullable;
// Use with collections
const listSerializer = ListSerializer(String.serializer());
const nullableListSerializer = listSerializer.nullable;class CustomUserSerializer {
constructor() {
this.descriptor = buildClassSerialDescriptor("CustomUser") {
element("fullName", String.serializer().descriptor)
element("birthYear", Int.serializer().descriptor)
};
}
serialize(encoder, value) {
const composite = encoder.beginStructure(this.descriptor);
composite.encodeStringElement(this.descriptor, 0, `${value.firstName} ${value.lastName}`);
composite.encodeIntElement(this.descriptor, 1, new Date().getFullYear() - value.age);
composite.endStructure(this.descriptor);
}
deserialize(decoder) {
const composite = decoder.beginStructure(this.descriptor);
let fullName = "";
let birthYear = 0;
while (true) {
const index = composite.decodeElementIndex(this.descriptor);
if (index === CompositeDecoder.DECODE_DONE) break;
switch (index) {
case 0:
fullName = composite.decodeStringElement(this.descriptor, 0);
break;
case 1:
birthYear = composite.decodeIntElement(this.descriptor, 1);
break;
default:
throw new SerializationException(`Unexpected index: ${index}`);
}
}
composite.endStructure(this.descriptor);
const parts = fullName.split(' ');
const age = new Date().getFullYear() - birthYear;
return new User(parts[0], parts[1], age);
}
}// Register with @Serializable
@Serializable(CustomUserSerializer::class)
class User {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
}
// Or use directly
const customSerializer = new CustomUserSerializer();
const json = format.encodeToString(customSerializer, user);
const decoded = format.decodeFromString(customSerializer, json);Serializers can throw specific exceptions:
class ValidatingSerializer {
serialize(encoder, value) {
if (!this.isValid(value)) {
throw new SerializationException("Invalid value for serialization");
}
// ... serialization logic
}
deserialize(decoder) {
const result = /* ... deserialization logic */;
if (!this.isValid(result)) {
throw new SerializationException("Deserialized value failed validation");
}
return result;
}
isValid(value) {
// Validation logic
return value !== null && value !== undefined;
}
}Serializers maintain full type safety in TypeScript:
// Typed serializer creation
const userSerializer: KSerializer<User> = User.serializer();
const listSerializer: KSerializer<Array<User>> = ListSerializer(userSerializer);
// Generic serializer functions
function serializeList<T>(serializer: KSerializer<T>, items: T[]): string {
const listSer = ListSerializer(serializer);
return format.encodeToString(listSer, items);
}
// Type-safe usage
const users: User[] = [new User("John", 30), new User("Jane", 25)];
const json: string = serializeList(User.serializer(), users);The serializer system provides the foundation for all serialization operations while maintaining type safety and performance across different formats and use cases.
Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-serialization-core-js