Ecosystem

kotlinx.serialization 1.2 Released: High-Speed JSON Handling, Value Class Support, Overhauled Docs, and more

Read this post in other languages:

kotlinx.serialization 1.2 is out! The latest version of our multiplatform serialization library brings a number of improvements – here are the highlights:

Version 1.2 also includes new support for alternative names for JSON fields, and it provides a new experimental approach that automatically generates Protobuf schemas from Kotlin classes, a feature for which we’re eager to receive your feedback!

Let’s explore the changes and additions in this new version together! If you’re already convinced, you can of course also jump directly to the upgrade instructions below!

Start using kotlinx.serialization 1.2!


Subscribe to Kotlin YouTube!

Faster-than-ever JSON encoding and decoding

The ability to encode Kotlin classes to JSON strings and the ability to turn JSON strings into Kotlin classes are the most commonly used features of kotlinx.serialization, and we’re constantly working to improve their performance.

Parsing JSON with kotlinx.serialization: Up to 55 percent faster

Version 1.2 completely overhauls the internal structure of kotlinx.serialization, resulting in significantly better performance for this core functionality. We have rewritten our JSON decoder (responsible for turning text into Kotlin objects), and we’ve made significant optimizations to our JSON encoder (responsible for turning Kotlin objects into text).

Encoding JSON with kotlinx.serialization: Up to 339 percent faster

Just by upgrading to the latest version of our library, you can expect up to double the speed for typical encoding and decoding tasks. (As you can see, some of our internal benchmarks, which were particularly affected by these new optimizations, even exceed that number!)

With these changes, kotlinx.serialization achieves (and in some ways exceeds) performance parity with other JSON libraries right out of the box. Even the simplest snippets benefit from this overhaul:

The best way to get a feeling for these improvements is to benchmark your own application with the newest version of our library. For some rough performance numbers, you can have a look at our internal benchmarks for encoding and decoding, which compare the latest version of kotlinx.serialization to its previous release.

Stable JSON (de)serialization for value classes and unsigned number types

Kotlin 1.5.0 provides two exciting additions, value classes and unsigned integer types, for which kotlinx.serialization 1.2 now offers first-class JSON encoding and decoding support. Let’s take a closer look.

Support for value classes

Value classes (formerly called inline classes) are a way to wrap another Kotlin type (for example, a number) in a type-safe manner without introducing additional runtime overhead. This helps make your programs more expressive and safe without incurring performance penalties.

kotlinx.serialization’s built-in JSON serialization now works for value classes. Just like other Kotlin classes, we just have to annotate a value class with @Serializable.

Value classes are stored (and serialized) directly as their underlying type. We can see this by adding a field with a value class type to a serializable data class, and inspecting its output:

In the example above, NamedColor treats the value class Color as the underlying primitive (an Int). This means you get to enjoy maximum type-safety inside your Kotlin code, while still benefiting from a concise serialized representation of these types, without unnecessary boxing or nesting.

We’re still refining the design for hand-written, custom serializers for value classes, and they remain experimental for now. You can find out more on this topic in docs on GitHub.

Support for unsigned integers

Unsigned integers are an addition to the Kotlin standard library that provide types and operations for non-negative numbers. With the release of Kotlin 1.5.0, the following unsigned number types are available:

  • UByte, with values from 0 to 255
  • UShort, with values from 0 to 65535
  • UInt, with values from 0 to 2^32 – 1
  • ULong, with values from 0 to 2^64 – 1

The JSON encoder and decoder in kotlinx.serialization now supports these types out of the box. Just like other number types, unsigned integer values will be serialized in their plain number representation (the same representation you see when invoking .toString), without truncation, wrapping, or conversion to signed types.

Please note that support for value classes and unsigned integers is currently available for JSON. In a future release, we will also provide direct integrations for CBOR and Protobuf – stay tuned!

If you want to stay up-to-date with future releases of kotlinx.serialization and the Kotlin programming language, subscribe to the Kotlin product updates newsletter via the form next to this blog post!

For more detailed information on using value classes and unsigned types with kotlinx.serialization, have a look at the documentation on GitHub.

Alternative name support for JSON fields

Sometimes, you need to parse JSON fields that have different names but the same meaning, for example, to maintain backwards compatibility. With the new @JsonNames annotation, you can now give JSON fields alternative names, which will be used during the decoding process.

To illustrate this, let’s look at an example. Let’s assume that depending on its version, a server gives us one of the two following responses:

Both name and title have the same meaning, and we want to map them to the same field in our Kotlin class. With the new @JsonNames annotation, we can specify title as an alternative key for the name key:

Notice how this is different from the @SerialName annotation, which allows you to rename fields for both encoding and decoding, but does not allow you to specify alternatives.

We hope that this feature will make it easier for you to work with services that return differently named fields representing the same values, survive schema migrations, and provide graceful upgrades for your applications!

Fresh API documentation

To make your experience learning kotlinx.serialization as comfortable and fun as possible, we try to provide you with a number of reference materials. One of them is the Kotlin Serialization Guide on GitHub, which offers a walkthrough for the functionality provided by the library and includes self-contained examples to give you an intuitive understanding of each feature.

Another is the kotlinx.serialization API documentation, which we have completely overhauled. Based on a new version of Dokka, the Kotlin documentation engine, the new API documentation comes in a new responsive and modern design and easy-to-navigate symbols.

Example of the new API docs, showing the JsonElement documentation

Explore the new kotlinx.serialization API documentation!

Protobuf: experimental schema generation from Kotlin classes

Protocol Buffers (Protobuf) is a binary serialization format for structured data created by Google. As a binary format, it is more space-efficient than JSON or XML, while still providing a language-agnostic structure which you can use for application-to-application communication.

With kotlinx.serialization, you can use multiplatform Protobuf serialization (using proto2 semantics) with experimental stability. Like the other formats, you annotate your class as @Serializable and use the builtin encode / decode methods:

With your Kotlin classes as the source of truth (together with any customizations you might want to apply), kotlinx.serialization is able to infer the binary schema of the data, making Protobuf communication between multiple Kotlin applications concise and convenient.

kotlinx.serialization 1.2 now also includes an experimental schema generator for Protocol Buffers. It allows you to generate .proto files from your Kotlin data classes, which in turn can be used to generate representations of your communication schema in other languages, including Python, C++, and TypeScript.

For instructions on how to get started with the new schema generator, check out the corresponding instructions in the documentation.

Once the .proto file has been generated, you can store it in your repository and use it to generate representations of your Kotlin classes in other languages. We hope that this will make it easier for you to use kotlinx.serialization’s Protobuf integration in multi-language applications without having to give up the convenience of managing your schemas directly in Kotlin source code.

Because this is the first iteration of the Protobuf schema generator, we heavily rely on your feedback. Please give it a try, and tell us about your use cases, how you manage your models and .proto files, any problems you encounter, and the features you’d like to see, using the GitHub issue tracker.

When working with the schema generator, please keep some of its limitations in mind. As a rule of thumb, if a Kotlin class can be serialized with the protobuf implementation included with kotlinx.serialization, then the schema generator will provide support for it. This also means that the same restrictions apply. Here are some points to be on the lookout for:

  • Kotlin classes and property names need to conform to the protobuf specification, and don’t contain illegal characters.
  • Kotlin’s nullability is not reflected in the schema (because proto2 does not have semantics for it). Optional fields as provided by protocol buffers are used based on whether your Kotlin properties define default values.
  • Kotlin default values are not included in the schema. (meaning you will have to ensure the consistency of defaults in different language implementations by yourself.)

Start using kotlinx.serialization 1.2!

That concludes our overview! If you’re ready to enjoy faster JSON encoding and decoding, support for Kotlin 1.5 type system additions, Protobuf schema generation, and more, then it’s time to upgrade!

If you’re already using kotlinx.serialization, upgrading to version 1.2 is very quick (and if you haven’t tried kotlinx.serialization before, now is a great time to get started!). First, update the plugins block in your build.gradle.kts file:

Then, update your dependencies block with the runtime library, including the formats you want to use in your application:

Watch and read more

If you run into any trouble

Subscribe to Kotlin YouTube! Happy (de)serializing!

image description