В огромном приложении Android с Clean Architecture много рутинной работы, связанной с отображением объектов между различными слоями. Хорошим решением будет автоматизация этого процесса.
В этой статье рассматривается опыт использования библиотеки MapStruct, которая помогает mapp-ить объекты.
Библиотека очень гибка в настройке. И позволяет минимизировать написание шаблонного кода.
Вот пример того, как реализовать gradle зависимости в вашем проекте.
plugins {
kotlin("kapt") version "1.9.22"
}
dependencies {
implementation("org.mapstruct:mapstruct:1.6.0")
kapt("org.mapstruct:mapstruct-processor:1.6.0")
}
Нажмите Синхронизировать ваш проект и начнем с самого простого и элементарного примера. Допустим, у нас есть два объекта:
data class PersonResponse(
val id: Long,
val name: String,
val birthday: String
)
data class Person(
val id: Long,
val name: String,
val birthday: String,
)
Для создания mapper-a нам необходимо создать интерфейс:
@Mapper
interface MapperPerson {
fun userResponseToUser(userResponse: PersonResponse): Person
companion object {
val INSTANCE = Mappers.getMapper(MapperPerson::class.java)
}
}
Вот и все! Mapping уже работает.
@Test
fun `test map PersonResponse to Person`() {
val response = PersonResponse(1, "John", "2024.01.01")
val person = MapperPerson.INSTANCE.personResponseToPerson(response)
assert(person.name == "John")
}
Mapping вложенного объекта
Давайте рассмотрим немного более сложный случай.
data class PersonResponse(
val id: Long,
val name: String,
val birthday: String,
val educationResponse: EducationResponse
)
data class EducationResponse(
val universityName: String
)
data class Person(
val id: Long,
val name: String,
val birthday: String,
val education: Education
)
data class Education(
val universityName: String
)
Поэтому нам нужно изменить mapper следующим образом:
@Mapper(uses = [MapperEducation::class])
interface MapperPerson {
@Mapping(source = "userResponse.educationResponse", target = "education")
fun personResponseToPerson(userResponse: PersonResponse): Person
companion object {
val INSTANCE = Mappers.getMapper(MapperPerson::class.java)
}
}
@Mapper
interface MapperEducation {
fun map(educationResponse: EducationResponse) : Education
}
И тест пройден.
@Test
fun `test map PersonResponse to Person`() {
val response = PersonResponse(
id = 1,
name = "John",
birthday = "2024.01.01",
educationResponse = EducationResponse("University")
)
val person = MapperPerson.INSTANCE.personResponseToPerson(response)
assert(person.name == "John")
}
В статье рассмотрены базовые случаи mapping-a с использованием библиотеки MapStruct. Более сложные случаи будут рассмотрены в следующих статьях. Спасибо за внимание!