Mapping Objects with MapStruct

In a huge Android app with Clean Architecture, there is a lot of routine work related to displaying objects between different layers. A good solution would be to automate this process.

This article discusses the experience of using the library. MapStructwhich helps to map objects.

The library is very flexible in configuration. And allows you to minimize the writing of template code.

Here is an example of how to implement gradle dependencies in your project.

plugins {
   kotlin("kapt") version "1.9.22"
}
dependencies {
   implementation("org.mapstruct:mapstruct:1.6.0")
   kapt("org.mapstruct:mapstruct-processor:1.6.0")
}

Click Sync your project and let's start with the simplest and most basic example. Let's say we have two objects:

data class PersonResponse(
   val id: Long,
   val name: String,
   val birthday: String
)
data class Person(
   val id: Long,
   val name: String,
   val birthday: String,
)

To create a mapper we need to create an interface:

@Mapper
interface MapperPerson {
  
    fun userResponseToUser(userResponse: PersonResponse): Person
  
companion object {
    val INSTANCE = Mappers.getMapper(MapperPerson::class.java)
   }
}

That's it! Mapping is already working.

@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 a nested object

Let's look at a slightly more complex case.

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
)

So we need to change the mapper as follows:

@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
  
}

And the test is passed.

@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")
}

The article covers basic mapping cases using the MapStruct library. More complex cases will be covered in future articles. Thank you for your attention!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *