Data-классы в Kotlin
Если вы Android-инженер и задумались над переходом с Java на Kotlin, эта заметка вам пригодится.
Ещё до того, как в Google решили объявить поддержку Kotlin на официальном уровне, нередко можно было увидеть среди рекомендаций по переходу с Java на Kotlin начать процесс перехода именно с написания unit-тестов на этом языке. Действительно, unit-тесты — наименее агрессивный путь экспансии Котлин на кодовую базу, однако вы вряд ли вы испытаете удовольствие от «сладкого» и лаконичного синтаксиса Kotlin, подталкивающее к приёмам функционального программирования, ведь в большинстве случаев unit-тесты — это императивный стиль. Но вы можете попробовать параллельно делать вкрапления языка с написания POJO посредством data-классов. О них и поговорим.
Допустим, вам необходимо написать класс сущности для фильма Movie. Воспользовавшись дата-классами, вы обойдётесь всего одной строчкой кода:
data class Movie(val id: Long, val title: String, val director: String, val releaseDate: Date)
Что вы тут получаете помимо лаконичности:
— переопределённые методы
Movie(42L, "Isle of Dogs", "Wes Anderson", Date())
— метод
val clonedMovie = existingMovie.copy(id = 43L)
Примечание № 1: во время создания экземпляра такого класса на Java посредством
data class Movie(val id: Long = 0L, val title: String = "", val director: String = "", val releaseDate: Date, val description: String? = null) ... val movie = Movie(releaseDate = Date(), title = "The Darjeeling Limited")
Однако учтите, что data-классы пока не могут наследоваться друг от друга. Но вам могут пригодиться неявно абстрактные sealed-классы. Допустим, тогда, когда нужно определить разные состояния загрузки данных либо экрана. И в любых других ситуациях, в которых уместны ограниченные иерархии классов.
Data-классы + Parcelable
Уже начиная с версии 1.1.4, отсутствует необходимость писать boilerplate-реализации методов parcelable для поддержки сериализации и десериализации ваших объектов, ведь за вас это делает аннотация @Parcelize.
@Parcelize data class Movie(val id: Long, val title: String, val director: String, val releaseDate: Date)
Просто не забудьте применить плагин Android Extensions:
apply plugin: 'kotlin-android-extensions'
А также надо будет определить значение experimental-флага как true.
android { ... androidExtensions { experimental = true } }
Data-классы и часто используемые библиотеки
Если вы любите использовать такую замечательную библиотеку, как Room Persistence Library, вы всё так же при подключённом kapt сможете писать data-классы для сущностей вашей БД, которые отлично работают с Room-аннотациями.
@Entity(tableName = "movies") data class Movie( @PrimaryKey @ColumnInfo(name = "id") val id: Long, @ColumnInfo(name = "title") val title: String, @ColumnInfo(name = "director") val director: String, @ColumnInfo(name = "date") val releaseDate: Long )
Нет проблем и с Nullable-свойствами.
Если же говорить о библиотеках для сериализации данных, в случае с одной из наиболее популярных в этой сфере GSON, необходимость в дополнительных конвертерах и плагинах отсутствует. Библиотека станет сериализовать ваши POJO с тем же успехом, как и в случае с Java-версией:
data class Movie( @SerializedName("id") val id: Long, @SerializedName("title") val title: String, @SerializedName("director") val director: String, @SerializedName("releaseDate") val releaseDate: Date )
Но, как и в случае с Room, не поддерживаются значения по умолчанию.
Также для совместимости Jackson c Kotlin надо добавить зависимость специального модуля.
Схожим образом обстоят дела и с Moshi, для совместимости с которым нужно добавить зависимость:
implementation 'com.squareup.moshi:moshi-kotlin:1.x.y'