CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Kotlin multiplatform JSON serialization library with JavaScript-specific dynamic object conversion capabilities

Pending
Overview
Eval results
Files

configuration.mddocs/

Configuration and Customization

Comprehensive configuration system for customizing JSON encoding/decoding behavior, naming strategies, and polymorphism handling. The JsonBuilder class provides extensive options to control how JSON serialization behaves.

Capabilities

JsonBuilder Configuration

Configure Json instances through the JsonBuilder class with extensive customization options.

/**
 * Builder class for configuring Json instances
 */
class JsonBuilder {
    /**
     * Encode default property values (default: false)
     */
    var encodeDefaults: Boolean
    
    /**
     * Explicitly encode/require null values (default: true)  
     */
    var explicitNulls: Boolean
    
    /**
     * Ignore unknown JSON properties during decoding (default: false)
     */
    var ignoreUnknownKeys: Boolean
    
    /**
     * Coerce invalid input values to defaults (default: false)
     */
    var coerceInputValues: Boolean
    
    /**
     * Enable pretty-printed JSON output (default: false)
     */
    var prettyPrint: Boolean
    
    /**
     * Indentation string for pretty printing (default: "    ")
     */
    var prettyPrintIndent: String
    
    /**
     * Allow malformed JSON (unquoted keys/values) (default: false)
     */
    var isLenient: Boolean
    
    /**
     * Allow NaN, Infinity values (default: false)
     */
    var allowSpecialFloatingPointValues: Boolean
    
    /**
     * Allow complex objects as map keys (default: false)
     */
    var allowStructuredMapKeys: Boolean
    
    /**
     * Allow trailing commas in objects/arrays (default: false)
     */
    var allowTrailingComma: Boolean
    
    /**
     * Allow C-style comments in JSON (default: false)
     */
    var allowComments: Boolean
    
    /**
     * Use @JsonNames alternative names (default: true)
     */
    var useAlternativeNames: Boolean
    
    /**
     * Global property name transformation (default: null)
     */
    var namingStrategy: JsonNamingStrategy?
    
    /**
     * Case-insensitive enum parsing (default: false)
     */
    var decodeEnumsCaseInsensitive: Boolean
    
    /**
     * Property name for type discriminator (default: "type")
     */
    var classDiscriminator: String
    
    /**
     * When to add discriminators (default: POLYMORPHIC)
     */
    var classDiscriminatorMode: ClassDiscriminatorMode
    
    /**
     * Use legacy array-based polymorphism (default: false)
     */
    var useArrayPolymorphism: Boolean
}

Encoding/Decoding Behavior

Control how objects are serialized and deserialized.

Usage Examples:

@Serializable
data class User(
    val name: String,
    val age: Int = 25,  // Default value
    val email: String? = null,
    val isActive: Boolean = true
)

// Default behavior
val defaultJson = Json.Default
val user = User("Alice")
val defaultResult = defaultJson.encodeToString(user)
// Result: {"name":"Alice"}
// Note: Default values and nulls are omitted

// Include default values
val includeDefaultsJson = Json {
    encodeDefaults = true
}
val withDefaults = includeDefaultsJson.encodeToString(user)
// Result: {"name":"Alice","age":25,"email":null,"isActive":true}

// Handle null values explicitly
val explicitNullsJson = Json {
    encodeDefaults = true
    explicitNulls = true
}
val userWithEmail = User("Bob", email = "bob@example.com")
val withExplicitNulls = explicitNullsJson.encodeToString(userWithEmail)
// Result: {"name":"Bob","age":25,"email":"bob@example.com","isActive":true}

val noExplicitNullsJson = Json {
    encodeDefaults = true
    explicitNulls = false
}
val withoutExplicitNulls = noExplicitNullsJson.encodeToString(userWithEmail)
// Result: {"name":"Bob","age":25,"email":"bob@example.com","isActive":true}
// Note: Non-null email is still included

Lenient Parsing

Handle malformed or non-standard JSON input.

/**
 * Configuration modes for handling malformed JSON
 */
enum class ClassDiscriminatorMode {
    NONE,           // Never add class discriminators
    POLYMORPHIC,    // Add discriminators for polymorphic classes only
    ALL_JSON_OBJECTS // Add discriminators for all JSON objects
}

Usage Examples:

// Strict JSON parsing (default)
val strictJson = Json.Default

// Lenient JSON parsing
val lenientJson = Json {
    isLenient = true
    ignoreUnknownKeys = true
    coerceInputValues = true
    allowSpecialFloatingPointValues = true
    allowTrailingComma = true
    allowComments = true
}

// Malformed JSON examples that work with lenient parsing
val malformedJson = """
{
    // This is a comment
    unquoted_key: "value",
    "number": NaN,
    "infinity": Infinity,
    "trailing": "comma",
}
"""

try {
    val parsed = lenientJson.decodeFromString<JsonElement>(malformedJson)
    println("Lenient parsing succeeded")
} catch (e: JsonDecodingException) {
    println("Lenient parsing failed: ${e.message}")
}

// Coercing invalid values
@Serializable
data class NumberData(val value: Int, val flag: Boolean)

val invalidDataJson = """{"value": "not_a_number", "flag": "yes"}"""

val coercingJson = Json {
    coerceInputValues = true
}

val coercedData = coercingJson.decodeFromString<NumberData>(invalidDataJson)
// Result: NumberData(value = 0, flag = false) - invalid values coerced to defaults

Pretty Printing

Format JSON output for human readability.

Usage Examples:

@Serializable
data class Product(
    val id: String,
    val name: String,
    val categories: List<String>,
    val metadata: Map<String, String>
)

val product = Product(
    id = "PROD-001",
    name = "Super Widget",
    categories = listOf("electronics", "gadgets"),
    metadata = mapOf("color" to "blue", "weight" to "1.5kg")
)

// Compact output (default)
val compactJson = Json.Default
val compact = compactJson.encodeToString(product)
// Result: {"id":"PROD-001","name":"Super Widget","categories":["electronics","gadgets"],"metadata":{"color":"blue","weight":"1.5kg"}}

// Pretty printed output  
val prettyJson = Json {
    prettyPrint = true
}
val pretty = prettyJson.encodeToString(product)
// Result:
// {
//     "id": "PROD-001",
//     "name": "Super Widget", 
//     "categories": [
//         "electronics",
//         "gadgets"
//     ],
//     "metadata": {
//         "color": "blue",
//         "weight": "1.5kg"
//     }
// }

// Custom indentation
val customIndentJson = Json {
    prettyPrint = true
    prettyPrintIndent = "  " // 2 spaces instead of 4
}
val customIndent = customIndentJson.encodeToString(product)

Naming Strategies

Transform property names during serialization/deserialization.

/**
 * Strategy for transforming property names
 */
interface JsonNamingStrategy {
    /**
     * Transform a serial name for JSON serialization
     * @param descriptor Serial descriptor of the class
     * @param elementIndex Index of the property in the class
     * @param serialName Original property name
     * @return Transformed property name for JSON
     */
    fun serialNameForJson(descriptor: SerialDescriptor, elementIndex: Int, serialName: String): String
    
    companion object {
        /**
         * Convert camelCase to snake_case
         */
        val SnakeCase: JsonNamingStrategy
        
        /**
         * Convert camelCase to kebab-case
         */
        val KebabCase: JsonNamingStrategy
    }
}

Usage Examples:

@Serializable
data class ApiResponse(
    val userId: Int,
    val firstName: String,
    val lastName: String,
    val emailAddress: String,
    val isActiveUser: Boolean
)

val response = ApiResponse(
    userId = 123,
    firstName = "Alice",
    lastName = "Smith", 
    emailAddress = "alice@example.com",
    isActiveUser = true
)

// Default naming (camelCase)
val defaultNaming = Json.Default
val camelCase = defaultNaming.encodeToString(response)
// Result: {"userId":123,"firstName":"Alice","lastName":"Smith","emailAddress":"alice@example.com","isActiveUser":true}

// Snake case naming
val snakeCaseJson = Json {
    namingStrategy = JsonNamingStrategy.SnakeCase
}
val snakeCase = snakeCaseJson.encodeToString(response)
// Result: {"user_id":123,"first_name":"Alice","last_name":"Smith","email_address":"alice@example.com","is_active_user":true}

// Kebab case naming  
val kebabCaseJson = Json {
    namingStrategy = JsonNamingStrategy.KebabCase
}
val kebabCase = kebabCaseJson.encodeToString(response)
// Result: {"user-id":123,"first-name":"Alice","last-name":"Smith","email-address":"alice@example.com","is-active-user":true}

// Custom naming strategy
val customNamingJson = Json {
    namingStrategy = object : JsonNamingStrategy {
        override fun serialNameForJson(descriptor: SerialDescriptor, elementIndex: Int, serialName: String): String {
            return serialName.uppercase() // Convert all property names to uppercase
        }
    }
}
val uppercase = customNamingJson.encodeToString(response)
// Result: {"USERID":123,"FIRSTNAME":"Alice","LASTNAME":"Smith","EMAILADDRESS":"alice@example.com","ISACTIVEUSER":true}

Alternative Names

Support multiple property names during deserialization.

Usage Examples:

@Serializable
data class User(
    @JsonNames("user_id", "id") 
    val userId: Int,
    
    @JsonNames("user_name", "username", "login")
    val name: String,
    
    @JsonNames("email_address", "mail")
    val email: String
)

val flexibleJson = Json {
    useAlternativeNames = true // Default is true
}

// All these JSON variations can be deserialized to the same User object
val json1 = """{"userId":1,"name":"Alice","email":"alice@example.com"}"""
val json2 = """{"user_id":1,"user_name":"Alice","email_address":"alice@example.com"}"""
val json3 = """{"id":1,"username":"Alice","mail":"alice@example.com"}"""
val json4 = """{"user_id":1,"login":"Alice","email":"alice@example.com"}"""

val user1 = flexibleJson.decodeFromString<User>(json1)
val user2 = flexibleJson.decodeFromString<User>(json2)
val user3 = flexibleJson.decodeFromString<User>(json3)
val user4 = flexibleJson.decodeFromString<User>(json4)

// All result in the same User object
assert(user1 == user2)
assert(user2 == user3)
assert(user3 == user4)

Enum Handling

Configure enum serialization and deserialization behavior.

Usage Examples:

@Serializable
enum class Status { ACTIVE, INACTIVE, PENDING }

@Serializable
data class Record(val id: Int, val status: Status)

// Case-sensitive enum parsing (default)
val strictEnumJson = Json.Default

// Case-insensitive enum parsing
val lenientEnumJson = Json {
    decodeEnumsCaseInsensitive = true
}

// These will work with case-insensitive parsing
val variations = listOf(
    """{"id":1,"status":"ACTIVE"}""",
    """{"id":1,"status":"active"}""",
    """{"id":1,"status":"Active"}""",
    """{"id":1,"status":"AcTiVe"}"""
)

variations.forEach { json ->
    try {
        val record = lenientEnumJson.decodeFromString<Record>(json)
        println("Parsed: $record")
    } catch (e: JsonDecodingException) {
        println("Failed to parse: $json")
    }
}

Polymorphism Configuration

Control polymorphic serialization behavior.

Usage Examples:

@Serializable
abstract class Animal {
    abstract 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 lives: Int) : Animal()

// Default polymorphic configuration
val defaultPolymorphicJson = Json {
    classDiscriminator = "type" // Default
    classDiscriminatorMode = ClassDiscriminatorMode.POLYMORPHIC // Default
}

val dog = Dog("Buddy", "Golden Retriever")
val polymorphicResult = defaultPolymorphicJson.encodeToString<Animal>(dog)
// Result: {"type":"dog","name":"Buddy","breed":"Golden Retriever"}

// Custom discriminator property name
val customDiscriminatorJson = Json {
    classDiscriminator = "objectType"
}

val customResult = customDiscriminatorJson.encodeToString<Animal>(dog)
// Result: {"objectType":"dog","name":"Buddy","breed":"Golden Retriever"}

// Array-based polymorphism (legacy)
val arrayPolymorphicJson = Json {
    useArrayPolymorphism = true
}

val arrayResult = arrayPolymorphicJson.encodeToString<Animal>(dog)
// Result: ["dog",{"name":"Buddy","breed":"Golden Retriever"}]

// Discriminator modes
val allObjectsJson = Json {
    classDiscriminatorMode = ClassDiscriminatorMode.ALL_JSON_OBJECTS
    classDiscriminator = "className"
}

@Serializable
data class SimpleData(val value: String)

val simpleData = SimpleData("test")
val withDiscriminator = allObjectsJson.encodeToString(simpleData)
// Result: {"className":"SimpleData","value":"test"}

Install with Tessl CLI

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

docs

builder-dsl.md

configuration.md

core-operations.md

custom-serializers.md

dynamic-conversion.md

index.md

json-annotations.md

json-element.md

tile.json