
Experimental library enabling JSON5 serialization and deserialization with support for polymorphic types, class discriminators, comment serialization, concise error messages, and duplicate key rejection.
This is an experimental JSON5 library for Kotlin/JVM and Kotlin/Native. It makes use of the kotlinx.serialization framework to serialize object hierarchies into standard-compliant JSON5 text and vice versa.
json5k is available on Maven Central:
plugins {
kotlin("jvm") version "1.8.10"
kotlin("plugin.serialization") version "1.8.10"
}
repositories {
mavenCentral()
}
dependencies {
implementation("io.github.xn32:json5k:0.3.0")
}Official versions are published for the following targets:
jvm
linuxX64, macosX64, iosX64, mingwX64
macosArm64, iosArm64, iosSimulatorArm64
Snapshot versions of the main branch are available from here.
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:7import 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' at position 1:26import 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' at position 1:3import 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:1import 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
}
]
}
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
}
See the unit tests for serialization and deserialization for more examples.
This is an experimental JSON5 library for Kotlin/JVM and Kotlin/Native. It makes use of the kotlinx.serialization framework to serialize object hierarchies into standard-compliant JSON5 text and vice versa.
json5k is available on Maven Central:
plugins {
kotlin("jvm") version "1.8.10"
kotlin("plugin.serialization") version "1.8.10"
}
repositories {
mavenCentral()
}
dependencies {
implementation("io.github.xn32:json5k:0.3.0")
}Official versions are published for the following targets:
jvm
linuxX64, macosX64, iosX64, mingwX64
macosArm64, iosArm64, iosSimulatorArm64
Snapshot versions of the main branch are available from here.
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:7import 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' at position 1:26import 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' at position 1:3import 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:1import 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
}
]
}
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
}
See the unit tests for serialization and deserialization for more examples.