CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Kotlin multiplatform reflectionless serialization library core module for JavaScript platform

Pending
Overview
Eval results
Files

descriptors.mddocs/

Serial Descriptors

Complete reference for SerialDescriptor and related APIs that describe the structure of serializable types in kotlinx.serialization-core-js.

Core Interface

SerialDescriptor

Primary interface for describing the structure of serializable types.

interface SerialDescriptor {
    val serialName: String
    val kind: SerialKind
    val elementsCount: Int
    
    fun getElementName(index: Int): String
    fun getElementIndex(name: String): Int  
    fun isElementOptional(index: Int): Boolean
    fun getElementDescriptor(index: Int): SerialDescriptor
    fun getElementAnnotations(index: Int): List<Annotation>
    fun isInline: Boolean
    
    val annotations: List<Annotation>
    val isNullable: Boolean
}

{ .api }

Usage:

// Get descriptor from serializer
const userSerializer = User.serializer();
const descriptor = userSerializer.descriptor;

// Inspect structure
console.log(descriptor.serialName);    // "User"
console.log(descriptor.kind);          // StructureKind.CLASS
console.log(descriptor.elementsCount); // 3

// Iterate elements
for (let i = 0; i < descriptor.elementsCount; i++) {
  const name = descriptor.getElementName(i);
  const elementDesc = descriptor.getElementDescriptor(i);
  const optional = descriptor.isElementOptional(i);
  console.log(`${name}: ${elementDesc.serialName} (optional: ${optional})`);
}

Serial Kinds

SerialKind

Base sealed class for categorizing different types of serializable structures.

sealed class SerialKind {
    final override fun toString(): String
}

{ .api }

PrimitiveKind

Represents primitive types that cannot be decomposed further.

sealed class PrimitiveKind : SerialKind() {
    object BOOLEAN : PrimitiveKind()
    object BYTE : PrimitiveKind()  
    object CHAR : PrimitiveKind()
    object SHORT : PrimitiveKind()
    object INT : PrimitiveKind()
    object LONG : PrimitiveKind()
    object FLOAT : PrimitiveKind()
    object DOUBLE : PrimitiveKind()
    object STRING : PrimitiveKind()
}

{ .api }

Usage:

// Check for primitive kinds
const stringDesc = String.serializer().descriptor;
console.log(stringDesc.kind === PrimitiveKind.STRING); // true

// Pattern matching on kind
function describePrimitive(descriptor) {
  switch (descriptor.kind) {
    case PrimitiveKind.BOOLEAN:
      return "Boolean primitive";
    case PrimitiveKind.STRING:
      return "String primitive";
    case PrimitiveKind.INT:
      return "Integer primitive";
    // ... other cases
    default:
      return "Not a primitive";
  }
}

StructureKind

Represents composite types with internal structure.

sealed class StructureKind : SerialKind() {
    object CLASS : StructureKind()
    object LIST : StructureKind()
    object MAP : StructureKind()
    object OBJECT : StructureKind()
}

{ .api }

Usage:

// Check structure types
const userDesc = User.serializer().descriptor;
console.log(userDesc.kind === StructureKind.CLASS); // true

const listDesc = ListSerializer(String.serializer()).descriptor;
console.log(listDesc.kind === StructureKind.LIST); // true

const mapDesc = MapSerializer(String.serializer(), Int.serializer()).descriptor;
console.log(mapDesc.kind === StructureKind.MAP); // true

PolymorphicKind

Represents types that support polymorphic serialization (Experimental).

@ExperimentalSerializationApi
sealed class PolymorphicKind : SerialKind() {
    object SEALED : PolymorphicKind()
    object OPEN : PolymorphicKind()
}

{ .api }

Usage:

// Sealed class descriptor
const resultDesc = Result.serializer().descriptor;
console.log(resultDesc.kind === PolymorphicKind.SEALED); // true

// Open polymorphic descriptor
const shapeDesc = PolymorphicSerializer(Shape::class).descriptor;
console.log(shapeDesc.kind === PolymorphicKind.OPEN); // true

Descriptor Factory Functions

buildClassSerialDescriptor

Factory function for creating class descriptors with a builder DSL.

fun buildClassSerialDescriptor(
    serialName: String,
    typeParameters: Array<SerialDescriptor> = emptyArray(),
    builderAction: ClassSerialDescriptorBuilder.() -> Unit = {}
): SerialDescriptor

{ .api }

Usage:

const userDescriptor = buildClassSerialDescriptor("User") {
  element("name", String.serializer().descriptor)
  element("age", Int.serializer().descriptor, isOptional = true)
  element("email", String.serializer().descriptor)
};

// With type parameters (for generic classes)
const pairDescriptor = buildClassSerialDescriptor("Pair", [
  String.serializer().descriptor,  // First type parameter
  Int.serializer().descriptor      // Second type parameter  
]) {
  element("first", getTypeParameter(0))  // Use first type parameter
  element("second", getTypeParameter(1)) // Use second type parameter
};

ClassSerialDescriptorBuilder

Builder class for constructing class descriptors.

class ClassSerialDescriptorBuilder(val serialName: String) {
    fun element(
        elementName: String, 
        descriptor: SerialDescriptor,
        annotations: List<Annotation> = emptyList(),
        isOptional: Boolean = false
    )
    
    fun getTypeParameter(index: Int): SerialDescriptor
}

{ .api }

Usage:

// Advanced builder usage
const advancedDescriptor = buildClassSerialDescriptor("AdvancedClass") {
  // Required element
  element("id", String.serializer().descriptor)
  
  // Optional element
  element("description", String.serializer().descriptor, isOptional = true)
  
  // Element with annotations
  element("timestamp", Long.serializer().descriptor, [
    SerialName("created_at")
  ])
  
  // Nested structure
  element("address", buildClassSerialDescriptor("Address") {
    element("street", String.serializer().descriptor)
    element("city", String.serializer().descriptor)
  })
};

PrimitiveSerialDescriptor

Factory for primitive descriptors.

fun PrimitiveSerialDescriptor(
    serialName: String, 
    kind: PrimitiveKind
): SerialDescriptor

{ .api }

Usage:

// Create custom primitive descriptor
const customStringDescriptor = PrimitiveSerialDescriptor(
  "CustomString",
  PrimitiveKind.STRING
);

// Use in serializer
class CustomStringSerializer {
  constructor() {
    this.descriptor = customStringDescriptor;
  }
  
  serialize(encoder, value) {
    encoder.encodeString(value.toString().toUpperCase());
  }
  
  deserialize(decoder) {
    return decoder.decodeString().toLowerCase();
  }
}

SerialDescriptor Factory (Wrapper)

Creates a descriptor that wraps another descriptor.

fun SerialDescriptor(
    serialName: String, 
    original: SerialDescriptor
): SerialDescriptor

{ .api }

Usage:

// Create wrapper descriptor with different name
const originalDesc = String.serializer().descriptor;
const wrappedDesc = SerialDescriptor("WrappedString", originalDesc);

console.log(wrappedDesc.serialName); // "WrappedString"  
console.log(wrappedDesc.kind);       // PrimitiveKind.STRING (from original)

Collection Descriptors

Specialized factory functions for collection descriptors (Experimental).

@ExperimentalSerializationApi
fun listSerialDescriptor(elementDescriptor: SerialDescriptor): SerialDescriptor

@ExperimentalSerializationApi  
inline fun <reified T> listSerialDescriptor(): SerialDescriptor

@ExperimentalSerializationApi
fun mapSerialDescriptor(
    keyDescriptor: SerialDescriptor, 
    valueDescriptor: SerialDescriptor
): SerialDescriptor

@ExperimentalSerializationApi
inline fun <reified K, reified V> mapSerialDescriptor(): SerialDescriptor

@ExperimentalSerializationApi
fun setSerialDescriptor(elementDescriptor: SerialDescriptor): SerialDescriptor

@ExperimentalSerializationApi
inline fun <reified T> setSerialDescriptor(): SerialDescriptor

{ .api }

Usage:

// Collection descriptors
const stringListDesc = listSerialDescriptor(String.serializer().descriptor);
const reifiedListDesc = listSerialDescriptor<String>();

const stringIntMapDesc = mapSerialDescriptor(
  String.serializer().descriptor,
  Int.serializer().descriptor
);
const reifiedMapDesc = mapSerialDescriptor<String, Int>();

const stringSetDesc = setSerialDescriptor(String.serializer().descriptor);
const reifiedSetDesc = setSerialDescriptor<String>();

Descriptor Utilities

serialDescriptor Functions

Retrieve descriptors for types.

inline fun <reified T> serialDescriptor(): SerialDescriptor

fun serialDescriptor(type: KType): SerialDescriptor

{ .api }

Usage:

// Get descriptor for reified type
const userDesc = serialDescriptor<User>();
const listDesc = serialDescriptor<List<String>>();

// Get descriptor for KType
const nullableStringType = typeOf<String?>();
const nullableStringDesc = serialDescriptor(nullableStringType);

Nullable Descriptors

val SerialDescriptor.nullable: SerialDescriptor

@ExperimentalSerializationApi
val SerialDescriptor.nonNullOriginal: SerialDescriptor

{ .api }

Usage:

const stringDesc = String.serializer().descriptor;
const nullableStringDesc = stringDesc.nullable;

console.log(stringDesc.isNullable);         // false
console.log(nullableStringDesc.isNullable); // true

// Get original non-null descriptor
const originalDesc = nullableStringDesc.nonNullOriginal;
console.log(originalDesc === stringDesc); // true

Iteration Utilities

val SerialDescriptor.elementDescriptors: Iterable<SerialDescriptor>
val SerialDescriptor.elementNames: Iterable<String>

{ .api }

Usage:

const userDesc = User.serializer().descriptor;

// Iterate element names
for (const name of userDesc.elementNames) {
  console.log(`Element: ${name}`);
}

// Iterate element descriptors
for (const [index, elementDesc] of userDesc.elementDescriptors.entries()) {
  console.log(`Element ${index}: ${elementDesc.serialName}`);
}

// Combined iteration
const names = Array.from(userDesc.elementNames);
const descriptors = Array.from(userDesc.elementDescriptors);

names.forEach((name, index) => {
  const desc = descriptors[index];
  console.log(`${name}: ${desc.kind}`);
});

Context-Aware Descriptors

Captured KClass

Access to the original KClass for contextual and polymorphic types (Experimental).

@ExperimentalSerializationApi
val SerialDescriptor.capturedKClass: KClass<*>?

{ .api }

Usage:

const polymorphicDesc = PolymorphicSerializer(Shape::class).descriptor;
const capturedClass = polymorphicDesc.capturedKClass;
console.log(capturedClass === Shape::class); // true

const contextualDesc = ContextualSerializer(Date::class).descriptor;
const dateClass = contextualDesc.capturedKClass;
console.log(dateClass === Date::class); // true

Module Context Functions

Retrieve contextual information from SerializersModule (Experimental).

@ExperimentalSerializationApi
fun SerializersModule.getContextualDescriptor(
    descriptor: SerialDescriptor
): SerialDescriptor?

@ExperimentalSerializationApi  
fun SerializersModule.getPolymorphicDescriptors(
    baseDescriptor: SerialDescriptor
): Collection<SerialDescriptor>

{ .api }

Usage:

const module = SerializersModule {
  contextual(Date::class, CustomDateSerializer)
  polymorphic(Shape::class) {
    subclass(Circle::class)
    subclass(Rectangle::class)
  }
};

// Get contextual descriptor
const dateDesc = Date::class.serializer().descriptor;
const contextualDesc = module.getContextualDescriptor(dateDesc);

// Get polymorphic descriptors
const shapeDesc = Shape::class.serializer().descriptor;
const subDescriptors = module.getPolymorphicDescriptors(shapeDesc);
console.log(subDescriptors.length); // 2 (Circle, Rectangle)

Descriptor Inspection

Complete Example

function inspectDescriptor(descriptor, indent = 0) {
  const spaces = ' '.repeat(indent);
  
  console.log(`${spaces}Name: ${descriptor.serialName}`);
  console.log(`${spaces}Kind: ${descriptor.kind}`);
  console.log(`${spaces}Nullable: ${descriptor.isNullable}`);
  console.log(`${spaces}Inline: ${descriptor.isInline}`);
  console.log(`${spaces}Elements: ${descriptor.elementsCount}`);
  
  if (descriptor.annotations.length > 0) {
    console.log(`${spaces}Annotations: ${descriptor.annotations.map(a => a.constructor.name)}`);
  }
  
  // Inspect elements for structured types
  if (descriptor.elementsCount > 0) {
    for (let i = 0; i < descriptor.elementsCount; i++) {
      const name = descriptor.getElementName(i);
      const optional = descriptor.isElementOptional(i);
      const elementDesc = descriptor.getElementDescriptor(i);
      const annotations = descriptor.getElementAnnotations(i);
      
      console.log(`${spaces}  [${i}] ${name}${optional ? '?' : ''}:`);
      if (annotations.length > 0) {
        console.log(`${spaces}    Annotations: ${annotations.map(a => a.constructor.name)}`);
      }
      
      // Recursive inspection for nested structures
      if (elementDesc.elementsCount > 0) {
        inspectDescriptor(elementDesc, indent + 4);
      } else {
        console.log(`${spaces}    Type: ${elementDesc.serialName} (${elementDesc.kind})`);
      }
    }
  }
}

// Usage
const userDescriptor = User.serializer().descriptor;
inspectDescriptor(userDescriptor);

TypeScript Type Guards

// Type guards for descriptor kinds
function isPrimitive(descriptor: SerialDescriptor): boolean {
  return descriptor.kind instanceof PrimitiveKind;
}

function isStructured(descriptor: SerialDescriptor): boolean {
  return descriptor.kind instanceof StructureKind;
}

function isPolymorphic(descriptor: SerialDescriptor): boolean {
  return descriptor.kind instanceof PolymorphicKind;
}

// Specific structure checks
function isClass(descriptor: SerialDescriptor): boolean {
  return descriptor.kind === StructureKind.CLASS;
}

function isList(descriptor: SerialDescriptor): boolean {
  return descriptor.kind === StructureKind.LIST;
}

function isMap(descriptor: SerialDescriptor): boolean {
  return descriptor.kind === StructureKind.MAP;
}

Serial descriptors provide complete introspection capabilities for serializable types, enabling format implementors and advanced users to understand and work with the structure of any serializable type at runtime.

Install with Tessl CLI

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

docs

annotations.md

builtins.md

descriptors.md

encoding.md

index.md

modules.md

serializers.md

tile.json