json5k
This is a JSON5 library for the kotlinx.serialization framework. Targeting the JVM, it serializes Kotlin object hierarchies into standard-compliant JSON5 output and vice versa.
Key features
- Compliance with v1.0.0 of the JSON5 specification
- Support for polymorphic types and configurable class discriminator names
- Carefully composed error messages for deserialization errors
- Support for the serialization of comments for class properties
- Rejection of duplicate keys during deserialization
Unit tests for the most important application scenarios exist, but the framework has not been deployed to production yet. In addition, benchmarking and performance optimization are still to be done.
Bug reports and other feedback are highly welcome, for example via the issue tracker on GitHub.
Setup instructions
This repository contains a Gradle setup that compiles the library into a JAR file. Use this file according to your needs.
Recommended versions
json5k was tested against the following dependencies:
json5k | Kotlin plugins | Serialization runtime |
---|---|---|
v0.2.0 | v1.7.20 | v1.4.1 |
v0.1.0 | v1.7.10 | v1.4.0 |
Usage from Gradle
For evaluation purposes, the easiest solution might be to install the library to your local Maven repository:
./gradlew publishToMavenLocal
Afterwards, use it from build.gradle.kts
as follows:
plugins {
kotlin("jvm") version "1.7.20"
kotlin("plugin.serialization") version "1.7.20"
}
repositories {
mavenLocal {
content {
includeGroup("io.github.xn32")
}
}
}
dependencies {
implementation("io.github.xn32:json5k:0.2.0")
}
However, keep the limitations of the local Maven repository in mind.
Usage examples
Non-hierarchical values
import io.github.xn32.json5k.Json5
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
// Serialization:
Json5.encodeToString(5142) // 5142
Json5.encodeToString(listOf(4.5, 1.5e2, 1.2e15)) // [4.5,150.0,1.2E15]
Json5.encodeToString(mapOf("a" to 10, "b" to 20)) // {a:10,b:20}
Json5.encodeToString(Double.NEGATIVE_INFINITY) // -Infinity
Json5.encodeToString<Int?>(null) // null
// Deserialization:
Json5.decodeFromString<Int?>("113") // 113
Json5.decodeFromString<List<Double>>("[1.2, .4]") // [1.2, 0.4]
Json5.decodeFromString<Map<String, Int>>("{ a: 10, 'b': 20, }") // {a=10, b=20}
Json5.decodeFromString<Double>("+Infinity") // Infinity
Json5.decodeFromString<Int?>("null") // null
// Deserialization errors:
Json5.decodeFromString<Byte>("190")
// UnexpectedValueError: signed integer in range [-128..127] expected at position 1:1
Json5.decodeFromString<List<Double>>("[ 1.0,,")
// CharError: unexpected character ',' at position 1:7
Serializable classes
import io.github.xn32.json5k.Json5
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@Serializable
data class Person(val name: String, val age: UInt? = null)
// Serialization:
Json5.encodeToString(Person("John", 31u)) // {name:"John",age:31}
Json5.encodeToString(Person("Jane")) // {name:"Jane"}
// Deserialization:
Json5.decodeFromString<Person>("{ name: 'Carl' }") // Person(name=Carl, age=null)
Json5.decodeFromString<Person>("{ name: 'Carl', age: 42 }") // Person(name=Carl, age=42)
// Deserialization errors:
Json5.decodeFromString<Person>("{ name: 'Carl', age: 42, age: 10 }")
// DuplicateKeyError: duplicate key 'age' specified at position 1:26
Classes with @SerialName
annotations
import io.github.xn32.json5k.Json5
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@Serializable
data class IntWrapper(@SerialName("integer") val int: Int)
// Serialization:
Json5.encodeToString(IntWrapper(10)) // {integer:10}
// Deserialization:
Json5.decodeFromString<IntWrapper>("{ integer: 10 }") // IntWrapper(int=10)
// Deserialization errors:
Json5.decodeFromString<IntWrapper>("{ int: 10 }")
// UnknownKeyError: unknown key 'int' specified at position 1:3
Polymorphic types
import io.github.xn32.json5k.ClassDiscriminator
import io.github.xn32.json5k.Json5
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@Serializable
@ClassDiscriminator("mode")
sealed interface Producer
@Serializable
@SerialName("numbers")
data class NumberProducer(val init: UInt) : Producer
// Serialization:
Json5.encodeToString<Producer>(NumberProducer(10u)) // {mode:"numbers",init:10}
// Deserialization:
Json5.decodeFromString<Producer>("{ init: 0, mode: 'numbers' }") // NumberProducer(init=0)
// Deserialization errors:
Json5.decodeFromString<Producer>("{ init: 0 }")
// MissingFieldError: missing field 'mode' in object at position 1:1
Serialization of comments for class properties
import io.github.xn32.json5k.Json5
import io.github.xn32.json5k.SerialComment
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
@Serializable
data class Person(
val name: String,
val age: UInt? = null
)
@Serializable
data class Event(
@SerialComment("First day of the event")
val date: String,
@SerialComment("Registered attendees")
val attendees: List<Person>
)
val json5 = Json5 {
prettyPrint = true
}
println(
json5.encodeToString(
Event("2022-10-04", listOf(Person("Emma", 31u)))
)
)
Running this code will produce the following output:
{
// First day of the event
date: "2022-10-04",
// Registered attendees
attendees: [
{
name: "Emma",
age: 31
}
]
}
Configuration options
Control generated JSON5 output as follows:
import io.github.xn32.json5k.Json5
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
val json5 = Json5 {
prettyPrint = true
indentationWidth = 2
useSingleQuotes = true
quoteMemberNames = true
encodeDefaults = true
}
@Serializable
data class Person(val name: String, val age: UInt? = null)
println(json5.encodeToString(Person("Oliver")))
This will result in the following output:
{
'name': 'Oliver',
'age': null
}
Further examples
See the unit tests for serialization and deserialization for more examples.