Вывод из статьи

В конце статьи вы узнаете, почему команда Kotlin создала новую библиотеку сериализации, несмотря на наличие многих продвинутых решений, таких как Moshi и Gson. Также вы узнаете, как ей правильно пользоваться, а в конце статьи ознакомитесь со скрытыми функциями встроенной сериализации.

Почему команда Kotlin создала новую библиотеку сериализации

Есть много известных и эффективных библиотек сериализации, таких как Moshi от Square и Gson от Google, но команда Kotlin решила создать совершенно новую собственную библиотеку сериализации для Kotlin. Вопрос — почему?

Библиотеки сериализации, такие как Moshi и Gson, являются Java-библиотеками, использующими рефлексии, что прекрасно подходит для Android разработки. Kotlin не ограничивается Android (JVM). Он поддерживает JavaScript и IOS (native) разработки. Рефлексииточно не сработают с Kotlin.js и нативными модулями. Кроме того, их использование в Android является недостатком.

Помимо мультиплатформенной поддержки и рефлексийв сериализации, существует еще один недостаток библиотек сериализации Java: они не поддерживают переменные значения в Kotlin по умолчанию. Для понимания, давайте начнем с простого класса данных, как показано ниже:

data class SimpleExample(val data : String,
                         var optionalData : String = "empty")

Когда мы пытаемся спарсить JSON только с узлом data, то значение optionalData изменяется на null вместо присвоения значения по умолчанию empty, объявленного в классе данных. Это большая проблема, потому что, когда переменная объявляется без вопросительного знака, компилятор Kotlin гарантирует, что переменная никогда не будет null, но обычные библиотеки сериализации Java об этом не знают. Этот тип функционального конфликта приводит к неожиданному поведению приложения.

Поэтому команда Kotlin решила создать библиотеку сериализации, которая работает со всеми платформами, поддерживающими этот язык, а также не имеет рефлексий.

Интеграция

Чтобы использовать библиотеку сериализации Kotlin, мы должны интегрировать как плагин сериализации, так и библиотеку среды выполнения. Плагин сериализации генерирует код для парсинга JSON без использования каких-либо рефлексий. Также библиотека среды выполнения использует этот код для сериализации классов данных.

Чтобы интегрировать модуль сериализации, добавьте следующую строку под всеми плагинами в первых строках файлаbuild.gradle уровня приложения.

apply plugin: 'kotlinx-serialization'

Также нужно добавить строку ниже под узлом зависимостей в файле build.gradle уровня проекта:

classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"

Затем добавьте следующую реализацию библиотеки под меткой зависимостей в файле build.gradle уровня приложения:

implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"

Как использовать сериализацию Kotlin с классами данных

С помощью этой нативной библиотеки от команды Kotlin сериализация может быть выполнена довольно быстро. Нам нужно добавить аннотацию @Serializable над предполагаемым классом. Обратите внимание:

@Serializable
data class SimpleExample(val data : String,
                         var optionalData : String = "empty")

Вот и все. Вам не нужно аннотироватькаждую переменную с помощью сериализуемых меток, как это делается в обычных библиотеках. 

Теперь давайте рассмотрим более реалистичный пример с Retrofit 2.

Retrofit 2 с kotlinx-сериализацией

Мы все знакомы с адаптерами retrofit для RxJava, Coroutines, Moshi и других библиотек. Аналогичным образом сериализация Kotlin так же имеет адаптер от JakeWharton, через который мы можем связать ответ retrofit с кодом сериализации Kotlin.

Чтобы интегрировать эту библиотеку в свой проект, добавьте строку ниже под узлом dependencies в файле build.gradle уровня приложения:

implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.5.0")

Теперь пришло время связать адаптер с инстансом retrofit. Взгляните на код ниже:

val contentType = "application/json".toMediaType()
val retrofit = Retrofit.Builder()
    .baseUrl(BuildConfig.BASE_URL)
    .addConverterFactory(serializationConverterFactory(contentType, JSON))
    .build()

Предполагая, что результирующий класс данных аннотируется меткой @Serializable, это все, что нам нужно сделать. Об остальном позаботится Kotlin Serialization Converter.

Cкрытые возможности

Безопасность во время компиляции

Это необходимо, когда вы выполняете некоторую сложную сериализацию, например, при вложении классов в класс данных ответа. Обратите внимание:

@Serializable
data class SimpleExample(val data : String,
                         var optionalData : String = "empty",
                         var complexClass: ComplexClass )

Хорошо, что вы аннотировали класс данных SimpleExample с помощью @Serializable, но что делать, если забыли аннотировать ComplexClass?Может ли это вызвать сбой во время выполнения? Или вы сами проверили, является ли каждый вложенный класс аннотированным или нет?

Расслабьтесь. Ни одна из вышеперечисленных ошибок не произойдет, потому что библиотека сериализации Kotlin безопасна во время компиляции, а это означает, что она показывает ошибку, если вы не аннотировали ни один из вложенных классов с помощью @Serializable, независимо от того, насколько глубока структура дерева.

Переходные и необязательные аннотации

Переходные: аннотируя переменную в классе данных как @Transient, мы говорим сериализатору, чтобы он полностью игнорировал это поле.

Необязательные: аннотируя переменную в классе данных как @Optional, мы указываем сериализатору, что она необязательна, поэтому не прерывайте процесс, если вы не нашли ее в ответе. Кроме того, мы можем назначить значение по умолчанию, как показано ниже.

@Optional                       
var isOptional: Boolean = false
@Transient                       
var isTransient: Boolean = false

Спасибо за чтение!

Читайте также:


Перевод статьи Siva Ganesh Kantamani: Why and How to Use Kotlin’s Native Serialization Library

Предыдущая статьяИнтерактивные отчеты в Jupyter Notebook
Следующая статьяКоманда Git Rerere — автоматизируйте решения для устранения конфликтов слияния