CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlinx--kotlinx-serialization-core-jvm

Kotlin multiplatform serialization runtime library core module with JVM target support

Pending
Overview
Eval results
Files

modules.mddocs/

Serialization Modules

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.

Capabilities

Core Module Classes

The fundamental classes for building and managing serializers modules.

/**
 * A collection of serializers used by ContextualSerializer and PolymorphicSerializer
 * to override or provide serializers at runtime. Acts as a registry for runtime serializer resolution.
 */
sealed class SerializersModule {
    /**
     * Returns a contextual serializer associated with the given class.
     * Used for types marked with @Contextual annotation.
     */
    fun <T : Any> getContextual(
        kClass: KClass<T>,
        typeArgumentsSerializers: List<KSerializer<*>> = emptyList()
    ): KSerializer<T>?
    
    /**
     * Returns a polymorphic serializer for the given base class and actual value.
     * Used for polymorphic serialization scenarios.
     */
    fun getPolymorphic(
        baseClass: KClass<Any>,
        value: Any
    ): SerializationStrategy<Any>?
    
    /**
     * Returns a polymorphic deserializer for the given base class and class discriminator.
     * Used during polymorphic deserialization.
     */
    fun getPolymorphic(
        baseClass: KClass<Any>,
        serializedClassName: String?
    ): DeserializationStrategy<out Any>?
}

/**
 * Builder class for creating SerializersModule using DSL syntax.
 * Provides methods for registering contextual and polymorphic serializers.
 */
class SerializersModuleBuilder : SerializersModuleCollector {
    /**
     * Builds the final SerializersModule from registered serializers.
     */
    fun build(): SerializersModule
}

/**
 * Builder for registering polymorphic serializers within the scope of a base class.
 * Provides type-safe registration of subclass serializers.
 */
class PolymorphicModuleBuilder<Base : Any> {
    /**
     * Register a subclass serializer for polymorphic serialization.
     */
    fun <T : Base> subclass(kClass: KClass<T>, serializer: KSerializer<T>)
    
    /**
     * Register a subclass serializer using reified type parameter.
     */
    inline fun <reified T : Base> subclass(serializer: KSerializer<T>)
    
    /**
     * Set a default serializer provider for unknown subclasses during serialization.
     */
    fun defaultSerializer(defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?)
    
    /**
     * Set a default deserializer provider for unknown subclasses during deserialization.
     */
    fun defaultDeserializer(defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?)
}

Module Builder Functions

Factory functions for creating SerializersModule instances.

/**
 * Creates a SerializersModule using DSL syntax.
 * The primary way to build modules with multiple serializers.
 * @param builderAction Lambda to configure the module
 * @return Configured SerializersModule
 */
fun SerializersModule(builderAction: SerializersModuleBuilder.() -> Unit): SerializersModule

/**
 * Creates a SerializersModule with a single contextual serializer.
 * @param kClass The class to register a serializer for
 * @param serializer The serializer to register
 * @return SerializersModule containing the single registration
 */
fun <T : Any> serializersModuleOf(kClass: KClass<T>, serializer: KSerializer<T>): SerializersModule

/**
 * Creates a SerializersModule with a single contextual serializer using reified type.
 * @param serializer The serializer to register
 * @return SerializersModule containing the single registration
 */
inline fun <reified T : Any> serializersModuleOf(serializer: KSerializer<T>): SerializersModule

/**
 * Returns an empty SerializersModule that contains no serializers.
 * @return Empty SerializersModule instance
 */
fun EmptySerializersModule(): SerializersModule

Contextual Serialization

Methods for registering serializers that are resolved based on usage context.

/**
 * Register a contextual serializer for the given class.
 * Used for types that need custom serialization but aren't marked @Serializable.
 * @param kClass The class to register a serializer for
 * @param serializer The serializer to use for the class
 */
fun <T : Any> SerializersModuleBuilder.contextual(kClass: KClass<T>, serializer: KSerializer<T>)

/**
 * Register a contextual serializer using reified type parameter.
 * @param serializer The serializer to use for type T
 */
inline fun <reified T : Any> SerializersModuleBuilder.contextual(serializer: KSerializer<T>)

/**
 * Register a contextual serializer provider for generic classes.
 * The provider receives type argument serializers and returns a configured serializer.
 * @param kClass The generic class to register a provider for
 * @param provider Function that creates serializers based on type arguments
 */
fun <T : Any> SerializersModuleBuilder.contextual(
    kClass: KClass<T>,
    provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
)

/**
 * Register a contextual serializer provider using reified type parameter.
 * @param provider Function that creates serializers based on type arguments
 */
inline fun <reified T : Any> SerializersModuleBuilder.contextual(
    provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
)

Usage Examples:

import kotlinx.serialization.*
import kotlinx.serialization.modules.*
import java.time.LocalDate
import java.util.UUID

// Custom serializers for external types
object LocalDateSerializer : KSerializer<LocalDate> {
    override val descriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)
    override fun serialize(encoder: Encoder, value: LocalDate) = encoder.encodeString(value.toString())
    override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString())
}

object UUIDSerializer : KSerializer<UUID> {
    override val descriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
    override fun serialize(encoder: Encoder, value: UUID) = encoder.encodeString(value.toString())
    override fun deserialize(decoder: Decoder): UUID = UUID.fromString(decoder.decodeString())
}

// Create module with contextual serializers
val module = SerializersModule {
    contextual(LocalDate::class, LocalDateSerializer)
    contextual(UUIDSerializer)  // Reified version for UUID
    
    // Generic contextual serializer  
    contextual(Box::class) { args ->
        BoxSerializer(args[0])  // args[0] is the serializer for T in Box<T>
    }
}

// Use with format
val json = Json { serializersModule = module }

@Serializable
data class Event(
    @Contextual val id: UUID,
    @Contextual val date: LocalDate,
    val name: String
)

Polymorphic Serialization

Methods for registering serializers for polymorphic type hierarchies.

/**
 * Register a polymorphic serializer for a subclass of the base class.
 * @param baseClass The polymorphic base class
 * @param actualClass The concrete subclass
 * @param actualSerializer The serializer for the subclass
 */
fun <Base : Any, Sub : Base> SerializersModuleBuilder.polymorphic(
    baseClass: KClass<Base>,
    actualClass: KClass<Sub>,
    actualSerializer: KSerializer<Sub>
)

/**
 * Configure polymorphic serialization for a base class using DSL.
 * @param baseClass The polymorphic base class
 * @param builderAction Lambda to configure subclass serializers
 */
fun <Base : Any> SerializersModuleBuilder.polymorphic(
    baseClass: KClass<Base>,
    builderAction: PolymorphicModuleBuilder<Base>.() -> Unit
)

/**
 * Configure polymorphic serialization using reified type parameter.
 * @param builderAction Lambda to configure subclass serializers
 */
inline fun <reified Base : Any> SerializersModuleBuilder.polymorphic(
    builderAction: PolymorphicModuleBuilder<Base>.() -> Unit
)

/**
 * Register a default serialization provider for unknown subclasses.
 * @param baseClass The polymorphic base class
 * @param defaultSerializerProvider Function to provide serializers for unknown types
 */
fun <Base : Any> SerializersModuleBuilder.polymorphicDefault(
    baseClass: KClass<Base>,
    defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?
)

/**
 * Register a default deserialization provider for unknown subclasses.
 * @param baseClass The polymorphic base class  
 * @param defaultDeserializerProvider Function to provide deserializers for unknown type names
 */
fun <Base : Any> SerializersModuleBuilder.polymorphicDefaultDeserializer(
    baseClass: KClass<Base>,
    defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
)

Usage Examples:

import kotlinx.serialization.*
import kotlinx.serialization.modules.*

// Polymorphic base interface
@Serializable
sealed interface Animal {
    val name: String
}

@Serializable
@SerialName("dog")
data class Dog(override val name: String, val breed: String) : Animal

@Serializable  
@SerialName("cat")
data class Cat(override val name: String, val indoor: Boolean) : Animal

// Register polymorphic serializers
val animalModule = SerializersModule {
    polymorphic(Animal::class) {
        subclass(Dog::class, Dog.serializer())
        subclass(Cat::class, Cat.serializer())
        
        // Default serializer for unknown animals
        defaultSerializer { animal ->
            when (animal) {
                is Dog -> Dog.serializer()
                is Cat -> Cat.serializer()
                else -> null
            }
        }
    }
}

// External polymorphic hierarchy (not sealed)
abstract class Shape
data class Circle(val radius: Double) : Shape()
data class Rectangle(val width: Double, val height: Double) : Shape()

val shapeModule = SerializersModule {
    polymorphic(Shape::class) {
        subclass(Circle::class, CircleSerializer)
        subclass(Rectangle::class, RectangleSerializer)
    }
}

Module Extension Functions

Functions for combining and manipulating SerializersModule instances.

/**
 * Combines two SerializersModule instances, with the right module taking precedence.
 * @param other The module to combine with this one
 * @return Combined SerializersModule
 */
operator fun SerializersModule.plus(other: SerializersModule): SerializersModule

/**
 * Combines two SerializersModule instances with explicit overwrite behavior.
 * The right module overwrites registrations from the left module.
 * @param other The module that will overwrite this one's registrations
 * @return Combined SerializersModule with overwrite behavior
 */
fun SerializersModule.overwriteWith(other: SerializersModule): SerializersModule

Usage Examples:

val baseModule = SerializersModule {
    contextual(UUID::class, UUIDSerializer)
}

val extendedModule = SerializersModule {
    contextual(LocalDate::class, LocalDateSerializer)
    polymorphic(Animal::class) {
        subclass(Dog.serializer())
        subclass(Cat.serializer())
    }
}

// Combine modules
val combinedModule = baseModule + extendedModule

// Override with explicit behavior
val overrideModule = SerializersModule {
    contextual(UUID::class, AlternativeUUIDSerializer)
}
val finalModule = baseModule.overwriteWith(overrideModule)

Module Introspection

Interface for examining the contents of SerializersModule instances.

/**
 * Interface that can introspect and accumulate the content of any SerializersModule.
 * Used for copying or analyzing module configurations.
 */
interface SerializersModuleCollector {
    /**
     * Add a contextual serializer to the collection.
     */
    fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>)
    
    /**
     * Add a contextual serializer provider to the collection.
     */
    fun <T : Any> contextual(
        kClass: KClass<T>, 
        provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>
    )
    
    /**
     * Add a polymorphic serializer to the collection.
     */
    fun <Base : Any, Sub : Base> polymorphic(
        baseClass: KClass<Base>,
        actualClass: KClass<Sub>,
        actualSerializer: KSerializer<Sub>
    )
}

Integration with Formats

SerializersModule is typically used when creating format instances:

import kotlinx.serialization.json.*

val customModule = SerializersModule {
    contextual(LocalDate::class, LocalDateSerializer)
    contextual(UUID::class, UUIDSerializer)
}

val json = Json {
    serializersModule = customModule
    // other format configuration
}

// All contextual types are now resolved using the module
val event = Event(UUID.randomUUID(), LocalDate.now(), "Conference")
val jsonString = json.encodeToString(event)
val decoded = json.decodeFromString<Event>(jsonString)

Error Handling

Common errors when working with SerializersModule:

  • SerializationException: Duplicate serializer registration for the same class
  • IllegalArgumentException: Invalid module configurations or missing serializers
  • ClassCastException: Type mismatches in polymorphic deserializer providers

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-serialization-core-jvm

docs

annotations.md

built-ins.md

core-serialization.md

descriptors.md

encoding.md

index.md

modules.md

tile.json