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:

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.

Start using kotlinx.serialization 1.3

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.

In 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:

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 true:

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.
  • NEVER doesn’t encode the default value regardless of the Json configuration.

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 MissingFieldException.

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

Read more