MapStruct

Overview

This article creates a project that uses MapStruct to copy values between classes.

The official MapStruct site is as follows.

Configuration

Add kapt to the build script’s plugins section as shown below.

/build.gradle.kts

plugins {
    kotlin("jvm") version "1.7.10"
    kotlin("kapt") version "1.5.10"
}

Add the related libraries and kapt to dependencies.

/build.gradle.kts

dependencies {
    testImplementation(kotlin("test"))

    implementation("org.mapstruct:mapstruct:1.5.2.Final")
    kapt("org.mapstruct:mapstruct-processor:1.5.2.Final")
}

Creating Data Classes

First, create the User domain class.

/src/main/kotlin/com/devkuma/mapstruct/domain/User.kt

package com.devkuma.mapstruct.domain

data class User(
    val name: String,
    val age: Int,
    val city: String?
)

Then create the UserDto class.

/src/main/kotlin/com/devkuma/mapstruct/domain/UserDto.kt

package com.devkuma.mapstruct.dto

data class UserDto(
    val name: String,
    val age: Int,
    val city: String?
)

Creating the Mapper Class

Create the mapper class. /src/main/kotlin/com/devkuma/mapstruct/mapper/UserDto.kt

package com.devkuma.mapstruct.mapper

import com.devkuma.mapstruct.dto.UserDto
import com.devkuma.mapstruct.domain.User
import org.mapstruct.Mapper
import org.mapstruct.factory.Mappers

@Mapper
interface UserMapper {

    fun convertToDto(s: User): UserDto

    fun convertToDomain(s: UserDto): User

    companion object {
        val INSTANCE: UserMapper = Mappers.getMapper(UserMapper::class.java)
    }
}

Creating Converter Functions in the Data Classes

Create the DTO converter function convertToDto() in the User domain class.

/src/main/kotlin/com/devkuma/mapstruct/domain/User.kt

package com.devkuma.mapstruct.domain

import com.devkuma.mapstruct.mapper.UserMapper

class User(
    val name: String,
    val age: Int,
    val city: String?
) {

    fun convertToDto() = UserMapper.INSTANCE.convertToDto(this)
}

Create the domain converter function convertToDomain() in the UserDto class.

/src/main/kotlin/com/devkuma/mapstruct/dto/UserDto.kt

package com.devkuma.mapstruct.dto

import com.devkuma.mapstruct.mapper.UserMapper

class UserDto(
    val name: String,
    val age: Int,
    val city: String?
) {

    fun convertToDomain() = UserMapper.INSTANCE.convertToDomain(this)
}

Creating Test Code

Create convertToDto() for the User domain class.

package com.devkuma.mapstruct.domain

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import kotlin.test.assertEquals

class UserTest {

    @Test
    fun convertToDto(){

        // Given
        var user = User(
            name = "devkuma",
            age = 20,
            city = "Seoul"
        )

        // When
        var userDto = user.convertToDto()

        // Then
        assertAll(
            { assertEquals(user.name, userDto.name) },
            { assertEquals(user.age, userDto.age) },
            { assertEquals(user.city, userDto.city) },
        )
    }
}

Create convertToDomain() for the UserDto class.

package com.devkuma.mapstruct.dto

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import kotlin.test.assertEquals

class UserDtoTest {

    @Test
    fun convertToDto(){

        // Given
        var userDto = UserDto(
            name = "devkuma",
            age = 20,
            city = "Seoul"
        )

        // When
        var user = userDto.convertToDomain()

        // Then
        assertAll(
            { assertEquals(userDto.name, user.name) },
            { assertEquals(userDto.age, user.age) },
            { assertEquals(userDto.city, user.city) },
        )
    }
}

Run both test classes and confirm that they do not fail.