-
Notifications
You must be signed in to change notification settings - Fork 661
Doc rewrite update 3 - Serialize built in types #3082
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: doc-restructuring-master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,378 @@ | ||
[//]: # (title: Serialize built-in types) | ||
|
||
The Kotlin serialization library supports various built-in types, including basic types such as primitives and strings, composite types, and several standard library classes. | ||
The following sections describe these types in detail and provide examples of how to serialize them. | ||
|
||
## Basic types | ||
|
||
Kotlin serialization provides built-in serializers for types that are represented as a single value in serialized data. | ||
This includes, primitives, strings, and enums. | ||
daniCsorbaJB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
For example, here’s how you can serialize a `Long` type: | ||
|
||
```kotlin | ||
// Imports the necessary library declarations | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
class Data(val signature: Long) | ||
|
||
fun main() { | ||
val data = Data(0x1CAFE2FEED0BABE0) | ||
println(Json.encodeToString(data)) | ||
// {"signature":2067120338512882656} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
### Numbers | ||
|
||
You can serialize all Kotlin number types, including integers and floating-point numbers, using their natural JSON representations: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
import kotlin.math.PI | ||
|
||
//sampleStart | ||
@Serializable | ||
class Data( | ||
val answer: Int, | ||
val pi: Double | ||
) | ||
|
||
fun main() { | ||
val data = Data(42, PI) | ||
println(Json.encodeToString(data)) | ||
// {"answer":42,"pi":3.141592653589793} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
### Long numbers as strings | ||
|
||
When you serialize Kotlin `Long` values to JSON, JavaScript's native number type can't represent the full range of a Kotlin `Long` type, | ||
leading to precision loss. | ||
Comment on lines
+58
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worthwhile to note that this is a limitation of JS, not Json that is effectively arbitrary precision? It is somewhat implied by the explanation below, but can be confusing in the distinction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point - it is a bit confusing - I restructured this part a bit:
|
||
|
||
Kotlin/JS handles these large `Long` numbers correctly, but JavaScript's native methods don't. | ||
A common workaround is to represent long numbers with full precision using the JSON string type. | ||
Kotlin Serialization supports this approach with [`LongAsStringSerializer`](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-long-as-string-serializer/). | ||
To apply it to a `Long` property, use the `@Serializable` annotation: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.builtins.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
class Data( | ||
@Serializable(with=LongAsStringSerializer::class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer removing explicit |
||
val signature: Long | ||
) | ||
|
||
fun main() { | ||
val data = Data(0x1CAFE2FEED0BABE0) | ||
println(Json.encodeToString(data)) | ||
// {"signature":"2067120338512882656"} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
> You can also specify serializers like `LongAsStringSerializer` for all properties in a file. | ||
> For more information, see [Specify serializers for a file](third-party-classes.md#specify-serializers-for-a-file). | ||
> | ||
{style="tip"} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it might worth it to add section aboun unsigned numbers here as well, given they're stable in stdlib and IR compiler has been default for years (https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/value-classes.md#unsigned-types-support-json-only). Just don't forget mentioning
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stating that unsigned is only unsigned in Json is inaccurate, other formats support unsigned directly (and at full range) - maybe something that the protobuf serializer can be extended to do. |
||
### Enum classes | ||
|
||
All `enum` classes are serializable by default without the `@Serializable` annotation. | ||
When serialized in JSON, an `enum` is encoded as a string: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
// The @Serializable annotation isn't required for enum classes | ||
enum class Status { SUPPORTED } | ||
|
||
@Serializable | ||
class Project(val name: String, val status: Status) | ||
|
||
fun main() { | ||
val data = Project("kotlinx.serialization", Status.SUPPORTED) | ||
println(Json.encodeToString(data)) | ||
// {"name":"kotlinx.serialization","status":"SUPPORTED"} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
> On Kotlin/JS and Kotlin/Native, you must use the `@Serializable` annotation for an `enum` class to use as a root object, | ||
> such as in `encodeToString<Status>(Status.SUPPORTED)`. | ||
> | ||
{style="note"} | ||
|
||
#### Customize serial names of enum entries | ||
|
||
> For more information on customizing serial names, see [Customize serial names](serialization-customization-options.md#customize-serial-names). | ||
> | ||
{style="tip"} | ||
|
||
To customize the serial names of enum entries, use the `@SerialName` annotation and mark the enum class with `@Serializable`: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
// Requires the @Serializable annotation because of @SerialName | ||
@Serializable | ||
enum class Status { @SerialName("maintained") SUPPORTED } | ||
|
||
@Serializable | ||
class Project(val name: String, val status: Status) | ||
|
||
fun main() { | ||
val data = Project("kotlinx.serialization", Status.SUPPORTED) | ||
println(Json.encodeToString(data)) | ||
// {"name":"kotlinx.serialization","status":"maintained"} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
## Composite types | ||
daniCsorbaJB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Kotlin Serialization supports several composite types from the standard library, but some classes, | ||
such as ranges and the [`Regex`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/) class aren't supported yet. | ||
daniCsorbaJB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Pair and triple | ||
|
||
You can serialize the [`Pair`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/) and [`Triple`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-triple/) classes from the Kotlin standard library: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
class Project(val name: String) | ||
|
||
fun main() { | ||
val pair = 1 to Project("kotlinx.serialization") | ||
println(Json.encodeToString(pair)) | ||
// {"first":1,"second":{"name":"kotlinx.serialization"}} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
### Collections | ||
|
||
Kotlin Serialization supports collection types such as [`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/), [`Set`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-set/), and [`Map`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rephrase this slightly. The thing is, we also support concrete implementations (e.g. And btw, regular |
||
Lists and sets are serialized as JSON arrays, and maps are represented as JSON objects. | ||
daniCsorbaJB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#### Serialize lists | ||
|
||
Kotlin Serialization serializes [`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/) types as JSON arrays. | ||
Here’s an example with a list of classes: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
class Project(val name: String) | ||
|
||
fun main() { | ||
val list = listOf( | ||
Project("kotlinx.serialization"), | ||
Project("kotlinx.coroutines") | ||
) | ||
println(Json.encodeToString(list)) | ||
// [{"name":"kotlinx.serialization"},{"name":"kotlinx.coroutines"}] | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
#### Serialize sets | ||
|
||
[`Set`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-set/) types are serialized as JSON arrays, just like [`List` types](#serialize-lists): | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
class Project(val name: String) | ||
|
||
fun main() { | ||
val set = setOf( | ||
Project("kotlinx.serialization"), | ||
Project("kotlinx.coroutines") | ||
) | ||
println(Json.encodeToString(set)) | ||
// [{"name":"kotlinx.serialization"},{"name":"kotlinx.coroutines"}] | ||
} | ||
//sampleEnd | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since Sets have their own section, maybe it is worth mentioning that
|
||
{kotlin-runnable="true"} | ||
|
||
#### Serialize maps | ||
|
||
Kotlin serialization supports [`Map`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/) types with primitive or enum keys: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
class Project(val name: String) | ||
|
||
fun main() { | ||
// Creates a map with Int keys | ||
val map = mapOf( | ||
1 to Project("kotlinx.serialization"), | ||
2 to Project("kotlinx.coroutines") | ||
) | ||
println(Json.encodeToString(map)) | ||
// {"1":{"name":"kotlinx.serialization"},"2":{"name":"kotlinx.coroutines"}} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
In JSON, maps are represented as objects. Since JSON object keys are always strings, keys are encoded as strings even if they are numbers in Kotlin. | ||
|
||
> JSON doesn't natively support complex or composite keys. | ||
> To encode structured objects as map keys, see [Encode structured map keys](serialization-json-configuration.md#encode-structured-map-keys). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can also add
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm 🤔 this one feels a bit fluffy to me, could you please clarify? what do we mean naturally? |
||
> | ||
{style="note"} | ||
Comment on lines
+258
to
+261
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe mention that other formats may support this in different ways. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the focus is on JSON here — unless we specify how it differs I think it might be just stating the obvious here. (to me it would read like: In JSON it works like this. In other formats it might work differently.) But if we have a very critical difference here, then I think we could list it. |
||
|
||
#### Deserialization behavior of collections | ||
|
||
Kotlin uses the declared type to deserialize JSON. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think original
explains what happens better. It also answers the question "What happens if I specify ArrayList or LinkedList" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although you can mention this in the beginning of the section, add the suggested tip to the Set section and drop this section completely. |
||
For example, a `List` preserves duplicates, while a `Set` enforces uniqueness: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
data class Data( | ||
val a: List<Int>, | ||
val b: Set<Int> | ||
) | ||
|
||
fun main() { | ||
val data = Json.decodeFromString<Data>(""" | ||
{ | ||
"a": [42, 42], | ||
"b": [42, 42] | ||
} | ||
""") | ||
// Duplicates are removed from data.b because Set enforces unique elements | ||
println(data) | ||
// Data(a=[42, 42], b=[42]) | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
> For more information about collections in Kotlin, see [Collections overview](collections-overview.md). | ||
> | ||
{style="tip"} | ||
|
||
## Unit and singleton objects | ||
|
||
The Kotlin [`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/) type and other singleton objects are serializable. | ||
A [singleton](object-declarations.md) is a class with only one instance, where the state is defined by the object itself rather than by external properties. | ||
In JSON, singleton objects are serialized as empty structures: | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
object SerializationVersion { | ||
val libraryVersion: String = "1.0.0" | ||
} | ||
|
||
fun main() { | ||
println(Json.encodeToString(SerializationVersion)) | ||
// {} | ||
println(Json.encodeToString(Unit)) | ||
// {} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
> You can use serialized singleton objects in [closed polymorphic hierarchies](serialization-polymorphism.md#serialize-objects-in-sealed-hierarchies) | ||
> to represent cases without additional fields. | ||
> | ||
{style="tip"} | ||
|
||
## Duration | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We also have two new serializers for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice one 💯 I added it to this section, so now it should be Duration and Instant(added |
||
|
||
Kotlin's [`Duration`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.time/-duration/) class is serialized to a JSON string using the ISO-8601-2 format: | ||
daniCsorbaJB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.json.* | ||
import kotlin.time.* | ||
|
||
//sampleStart | ||
fun main() { | ||
val duration = 1000.toDuration(DurationUnit.SECONDS) | ||
println(Json.encodeToString(duration)) | ||
// "PT16M40S" | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
## Nothing | ||
|
||
The [`Nothing`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-nothing.html) type is serializable by default. | ||
It has no instances, so encoding or decoding it throws an exception. | ||
Use `Nothing` when a type is syntactically required, but not involved in serialization, like in [polymorphic classes with generic base types](serialization-polymorphism.md#serialize-polymorphic-types-with-generic-base-types): | ||
|
||
```kotlin | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.builtins.* | ||
import kotlinx.serialization.json.* | ||
|
||
//sampleStart | ||
@Serializable | ||
sealed class ParametrizedParent<out R> { | ||
@Serializable | ||
data class ChildWithoutParameter(val value: Int) : ParametrizedParent<Nothing>() | ||
} | ||
|
||
fun main() { | ||
println(Json.encodeToString(ParametrizedParent.ChildWithoutParameter(42))) | ||
// {"value":42} | ||
} | ||
//sampleEnd | ||
``` | ||
{kotlin-runnable="true"} | ||
|
||
## What's next | ||
|
||
* Dive into the [Serialize classes](serialization-customization-options.md) section to learn how to serialize classes and how to modify the default behavior of the `@Serializable` annotation. | ||
* To explore more complex JSON serialization scenarios, see [JSON serialization overview](configure-json-serialization.md). | ||
* Learn more about polymorphism and serializing different types through a shared base in [Serialize polymorphic classes](serialization-polymorphism.md). |
Uh oh!
There was an error while loading. Please reload this page.