kotlinx.serialization 1.3 Released: Experimental IO Stream-Based JSON Serialization, Fine-Grained Defaults Control, and More
A new version of the Kotlin serialization library – 1.3.0 – is now available following the release of Kotlin 1.5.30. It mainly focuses on broadening the JSON serialization capabilities. Here are the most noticeable changes:
- Serializing and deserializing Java IO stream. You can now read and write JSON directly to network streams or files.
- More control over the encoding of default values. A new annotation defines the encoding of default values for each property separately.
- Exclusion of null values lets you minimize the resulting JSON by removing null property values and restoring them upon deserialization.
- Custom polymorphic class discriminators increase readability and add semantics to JSON when working with class hierarchies.
Read this blog post to learn about all these new features, or jump right to the How to try section to start exploring them for yourself.
Java IO stream-based JSON serialization
Serialization to Java IO streams and deserialization from them has been requested by our users for quite some time. The corresponding GitHub issue is one of the oldest in our repository and has received a huge number of upvotes.
kotlinx.serialization 1.3.0, we’re finally presenting the first experimental version of the serialization API for IO streams. With this API, you can decode objects directly from files, network streams, and other data sources without reading the data to strings beforehand. The opposite operation is also available: you can send encoded objects directly to files and other streams in a single API call.
IO stream serialization is currently available only on the JVM platform and for the JSON format.
The API includes two main methods:
- Json.decodeFromStream() reads an input stream and deserializes an object of the given type from it.
- Json.encodeToSteam() serializes an object and sends it into the given output stream.
This is how you can read a JSON object from a URL and write it to a file:
Note that only UTF-8 streams are currently supported.
This is just the first step, and there is still a lot of work to do. Please give the IO stream serialization API a try in your projects and share your feedback with us on the GitHub issue tracker.
Property-level control over default value encoding
kotlinx.serialization reduces the size of the JSON that results when serializing objects by omitting the default values of object properties. Default values are defined in the class declaration and automatically assigned if the corresponding property is not initialized in the code:
The JSON strings produced by a default
Json configuration won’t contain object properties with default values. When decoding such JSON strings, all omitted properties receive their default values as defined in the class declaration.
However, you can force the library to encode the default values by setting the
encodeDefaults property of a
Json instance to
This feature was already available, and in 1.3.0 we’re extending it by adding a new way to fine-tune the serialization of default values: you can now control it at the property level using the experimental
@EncodeDefault annotation. This has a higher priority level than the
encodeDefaults property and takes one of two possible values:
ALWAYS(default value) encodes a property value even if it is equal to the default.
NEVERdoesn’t encode the default value regardless of the
The encoding of the annotated properties is not affected by
encodeDefaults and works as described for all serialization formats, not only JSON.
Excluding null values from serialization
In 1.3.0, we’re introducing another way to reduce the size of the generated JSON strings – omitting null values.
A new JSON configuration property,
explicitNulls, defines whether
null property values should be included in the serialized JSON string. It’s
true by default, so all nulls are stored as the values of their corresponding properties.
You can make the resulting JSON shorter by excluding the null properties from serialization: just use a
Json instance with
explicitNulls = false:
The resulting JSON string contains only non-null properties.
To deserialize objects from JSON with omitted nulls, you also need a
Json instance with
explicitNulls == false. Such configuration sets all omitted nullable properties to
null unless they have default values. In this case, the default value is used. This is how the
json string from this snippet is decoded:
Trying to use a
Json configuration with
explicitNulls == true (the default setting) to decode a JSON string with omitted nulls will result in a
Custom polymorphic class discriminators
When it comes to class hierarchies, serialization may get a bit difficult because of the additional need to support polymorphism in serialization operations. There are recommended ways to deal with the serialization of hierarchies: make them sealed, annotate each class in the hierarchy as
@Serializable, and so on. This documentation page explains in detail how to handle such cases.
In hierarchy serialization, a useful attribute comes into play – class discriminator. It serves as a key for a property that stores the exact class of the object that was encoded. By default, the discriminator has the name
“type” and contains a fully qualified class name of the object being serialized, for example:
In previous versions, you could change the discriminator name using the classDiscriminator property of the
Json instance. Given the hierarchy above, you could write:
In 1.3.0, we’re adding a way to set a custom discriminator name for each class hierarchy to enable more flexible serialization. You can do this by marking a class with the new experimental annotation @JsonClassDiscriminator, using the discriminator name as its argument.
For example, you can use a word that somehow identifies the whole hierarchy to which an object belongs:
A custom discriminator applies to the annotated class and its subclasses. Only one custom discriminator can be used in each class hierarchy.
How to try
To enjoy the new JSON features in
kotlinx.serialization 1.3.0, apply the latest Kotlin serialization Gradle plugin (note that its version corresponds to Kotlin in general, not the library):
Then add or update the dependency on the JSON serialization library 1.3.0:
That’s it, you’re ready to go! Try the new features and let us know what you think of them.
If you run into any trouble
- Report issues to the GitHub issue tracker.
- Look for help in the #serialization channel on the Kotlin Slack (get an invite).