Kotlin
A concise multiplatform language developed by JetBrains
kotlinx.serialization 1.0 released
We are happy to share with you the release of version 1.0 of our multiplatform serialization library, kotlinx.serialization. As the first stable version of the library, we can finally consider it production-ready!
Whether you are writing Android apps, using Kotlin Multiplatform Mobile, creating server-side services, or building web frontends with Kotlin/JS – kotlinx.serialization comes with a simple but powerful pure-Kotlin API, which makes it effortless to parse JSON into type-safe Kotlin objects, and vice versa. To celebrate this release, we want to provide a brief overview of some of the production-ready features which are provided with kotlinx.serialization 1.0, and see what sets our library apart from other solutions.
If you want to get an exclusive behind-the-scenes look around kotlinx.serialization, you can also check out Leonid Startsev’s talk, who dives more deeply into the the design and behavior of the library.
Serializing & deserializing your first Kotlin object with kotlinx.serialization
Generally, serialization is a task that comes up quite frequently in software projects. Mobile apps or web frontends are likely to consume APIs which return JSON as a plain-text format for objects. Server-side applications and backend services often need to accept and respond to requests which are formatted using JSON. And even if you are looking to persist information on disk, using JSON as a human-readable format is a popular choice.
As you can see, the process of (de)serializing Kotlin objects is one that you might encounter sooner or later in your project as well. Choosing kotlinx.serialization makes this whole process very straightforward: After adding the library to your project, turning a basic Kotlin object into its JSON representation and back is as simple as marking its class with the @Serializable
annotation, and using the provided encodeToString
and decodeFromString<T>
extension functions on the Json
object:
Of course, kotlinx.serialization isn’t the only library you can use to perform such serialization-related tasks. In the JVM ecosystem, there are a number of other libraries to work with JSON. However, the most popular choices available are not necessarily Kotlin-first, and might not be available for Kotlin Multiplatform projects at all. Even beyond this, there are excellent reasons to choose kotlinx.serialization for your project.
Why choose kotlinx.serialization?
Several features and design choices included in kotlinx.serialization set it apart from other libraries, and generally help make it more enjoyable to use its functionality. Let’s take a closer look at a selection of them.
Kotlin through and through
Not only is kotlinx.serialization written in pure Kotlin, and available on all Kotlin Multiplatform targets, including Kotlin/Native and Kotlin/JS. Its serialization functionality is also built with the Kotlin type-system in mind. Whether you’re trying to serialize a data class
with default initializers for its properties, a singleton object
, or trying to deserialize a generic List<T>
: kotlinx.serialization always behaves as you would expect. This is best seen when looking at a concrete example, which turns a list of complex project objects (described by a data class
) into its JSON representation, and back:
As you can see, even the type-safe deserialization of collections with generics is handled by kotlinx.serialization just as expected. This certainly isn’t the norm, because collections on the JVM are normally affected by type erasure. As such, other libraries would require you to use workarounds like using explicit type-tokens in this situation. Because kotlinx.serialization also integrates using a compiler plugin, its out-of-the-box behavior (which you can see with the projectCollection
example) is already what you would expect – no workarounds required!
Because we want to make sure that you can catch as many possible issues before even starting your application for the first time, kotlinx.serialization also strives for compile-time safety. For example, not explicitly marking the Account
class to be @Serializable
in the example above would result in the compile-time error Serializer has not been found for type 'Account'
, making it easy to pinpoint and fix the issue ahead of time instead of experiencing a crash.
Polymorphic serialization
kotlinx.serialization makes it possible to comfortably and securely deal with inheritance hierarchies of objects to serialize – a traditionally sensitive, but much-desired feature. Because the library is aware of Kotlin-specific type system concepts, the most straightforward way to use polymorphic serialization is to build a sealed class hierarchy, where all subclasses are explicitly marked as @Serializable
. Because sealed class hierarchies are known at compile time, the kotlinx.serialization plugin can use this information, and the code required to serialize sub- and superclasses stays concise:
As you can see with the string variable, kotlinx.serialization intelligently adds a type key to your JSON object containing information about the specific subtype – without you having to specify this behavior manually. When you’re in control of both client and server, this makes it possible for you to easily structure messages using inheritance relationships, without having to manually try and deduce subtypes on the other end.
While sealed classes are the most convenient way to use polymorphic serialization with kotlinx.serialization, and can already cover a large number of use cases, the library actually also offers functionality that goes beyond these closed hierarchies. To learn more about this functionality, check out the section on polymorphism in the guide.
Strong customizability
Especially when communicating with external systems and APIs, you might not be in full control over the exact shape in which you receive JSON-formatted messages. On the other hand, you might feel the need to adjust the output that kotlinx.serialization generates to make sure it is accepted by the remote you are communicating with.
Kotlinx.serialization comes with a rich configuration DSL which you can use to adjust the way it generally treats input and generates output, modifying general settings like enabling pretty-printing, lenient parsing, or ignoring unknown keys. For class- or object-specific settings, you can use annotations to customize their behavior, for example, to rename fields (@SerialName
) or exclude them from the serialization process (@Transient
). These annotations, among a number of others, are also covered in the guide. If your use case requires it, you can even provide completely custom serializers for specific types of objects.
Combining these features allows you to shape the behavior of the library to exactly match the requirements and specifications you have for your serialized format.
Framework integrations
While kotlinx.serialization with its concise interfaces can be used regardless of other libraries included in a project, a number of frameworks also provide direct integrations to use kotlinx.serialization. Here are some examples we want to highlight:
- If you are using Ktor as a server-side framework, you can use the provided official integration with kotlinx.serialization together with content negotiation, making it possible to receive and respond with Kotlin objects directly for incoming and outgoing requests. The Ktor-Clients counterpart, which is available in Kotlin Multiplatform projects, also provides JSON payload processing via kotlinx.serialization.
- Spring MVC has recently added support for kotlinx.serialization, and a similar integration has been proposed for Spring WebFlux, thanks to Sébastien Deleuze.
- Http4k provides first class support for marshalling to and from HTTP messages using kotlinx.serialization.
- Fuel provides an extension package to use kotlinx.serialization in your Android HTTP client.
- If you are working with MongoDB, the KMongo library provides object mapping through kotlinx.serialization.
- If you are using Retrofit 2 to turn your HTTP APIs into Kotlin interfaces, you can use the serialization converter by Jake Wharton to integrate with kotlinx.serialization.
We are very excited about the growing number of third-party projects which integrate directly with kotlinx.serialization – and now that our library has reached a production-ready state, we hope to see many more such integrations soon!
Multi-format future
With version 1.0, all functionality related to working with JSON is stable and production-ready – but kotlinx.serialization is not stopping there! Besides JSON, the team is working on additional support for the HOCON, ProtoBuf, CBOR, and Properties serialization formats. While these formats are still being designed and developed, and as such have varying degrees of stability and platform compatibility, you can already try them out. They are available as separate artifacts, which you can find in the guide together with a short description of the format’s state.
A number of community-maintained formats like BSON, XML, and YAML also exist alongside the formats the team is working on officially – but please note that these are created and maintained by members of the community. Because creating custom formats is still an experimental feature and breaking changes are possible, they may receive delayed updates by their maintainers.
Now that we have highlighted a number of features that make kotlinx.serialization comfortable to use, we hope you have a good idea why you might want to choose the library for your current (or next) project – which is a quick process!
Adding kotlinx.serialization to your project
To start using kotlinx.serialization in your project, simply add the compiler plugin and runtime library to your project. In your build.gradle(.kts)
, add the following entry to the plugin
block:
Next, add the runtime library dependency to your dependencies block in your build.gradle(.kts)
file. If you are working in a Kotlin Multiplatform project, it’s enough to add the dependency to your common
target dependencies block – all platform-specific dependencies will automatically be added for you:
At this point, you’re ready to start using kotlinx.serialization! Feel free to experiment with the samples included in this blog post, try one of your own use cases, or play around with the examples which accompany the guide.
Learning more & giving feedback
We hope you enjoyed this brief overview of kotlinx.serialization! To find out more information, including always up-to-date installation instructions, visit its home on GitHub. Be sure to check out the kotlinx.serialization guide, which contains detailed information about basic and advanced features of the library, and covers many of the topics mentioned in this blog post in more detail. If you run into any trouble using the library, you can seek help in the project’s issue tracker, or in the #serialization channel on the Kotlin Slack.
If you have previously used kotlinx.serialization, use the changelog and migration guide to find out what has changed and how to upgrade your projects to the stable release.
For an exclusive look behind the scenes and a more in-depth explanation of our serialization library, check out the kotlinx.serialization talk by Leonid Startsev, which was held during the Kotlin 1.4 Online Event.
A thank you from the team
We want to say "thank you" to everyone who gave us feedback, submitted pull requests, used kotlinx.serialization pre-1.0, or contributed in any other way to the library. Your input was extremely valuable in helping the team deliver a robust, easy-to-use, Kotlin-first, multiplatform serialization library. The over 700 issues you reported before our first stable release helped squash bugs and iron out any wrinkles in the design before this first stable release. As we continue to evolve the project, we hope that we can count on your continued support and feedback to help us keep improving and innovating. So: Thank you, everyone – and have a nice Kotlin!