Spring

Java Bean Mapper 인 MapStruct 에 대해서 알아야 하는 한가지

kimc 2022. 1. 15. 13:27
반응형

 

이번 글을 통해 배워 갈 내용

  1. 자바 맵핑
  2. MapStruct에 대한 소개
  3. MapStruct 성능 소개
  4. MapStruct 사용법

자바 맵핑

Spring 서버에서 Object 맵핑을 하기 위해서

BeansUtil을 사용하거나 손으로 하나하나 Setter와 Getter로 설정을 하는 경우

 

매우 힘이 드는 일이다.

성능 저하를 최대한 줄이고 

 

Object Mapping을 할 때 하나하나 다 막일을 안 하려면

어떻게 해야 될까?

 

라고 고민을 한다면

MapStruct를 권장한다.


MapStruct에 대한 소개

MapStruct는 Annotation 기반으로 type-safe bean mapping 클래스를 제공하는 기능이다.

 

Mapping 되는 내용을 하나하나 다 적는 것보다 시간 절약이 되며

 

다른 동적 맵핑보다 시간 절약성, 컴파일 시간 안전성, 오류 내용 확인성 등에서 우월하다.

 


MapStruct 성능 소개

순수하게 get/set으로 진행한 경우와 MapStruct를 사용한 경우 둘 다 속도 측정을 해본 결과

비슷하게 나왔다.

 

BeansUtil보다는 한 객체를 변경하는 경우보다 100ms 정도 더 빨랐다.

 

따라서

MapStruct는 매우 빠르다

 


MapStruct 사용법

 

Maven에 MapStruct를 사용한다면

Maven Configuration을 아래와 같이 설정합니다.

...
<properties>
    <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>
...

 

Gradle에 MapStruct를 사용한다면

Gradle Configuration을 아래와 같이 설정합니다.

...
plugins {
    ...
    id "com.diffplug.eclipse.apt" version "3.26.0" // 이클립스라면 추가
}

dependencies {
    ...
    implementation "org.mapstruct:mapstruct:${mapstructVersion}"
    annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"

    // If you are using mapstruct in test code
    testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
}
...

 

Lombok을 MapStruct와 같이 사용한다면

Maven 은 아래와 같이 세팅해줍니다.

 

...
<properties>
        <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
        <org.projectlombok.version>1.18.16</org.projectlombok.version>
</properties>
...
<dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
        <!-- lombok dependency should not end up on classpath -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.version}</version>
            <scope>provided</scope>
        </dependency>
</dependencies>
...
<build>
    <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${org.projectlombok.version}</version>
                        </path>

                        <!-- additional annotation processor required as of Lombok 1.18.16 -->
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>0.1.0</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
    </plugins>
</build>
...

 

Gradle은 아래와 같이 세팅해줍니다.

dependencies {

    implementation "org.mapstruct:mapstruct:${mapstructVersion}"
    implementation "org.projectlombok:lombok:1.18.16"
    annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.1.0"
    annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
    annotationProcessor "org.projectlombok:lombok:1.18.16"
}

 

ExampleDto, ExampleEntity를 만들고

ExampleMapper를 이용해서 테스트해봤습니다.

import lombok.*;

@Getter
@Setter
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ExampleDto {
    private String name;
    private String description01;
    private String description02;
}
import lombok.*;

@Getter
@Setter
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ExampleEntity {
    private String name;
    private String description01;
    private String description02;
}
import org.mapstruct.Mapper;

@Mapper
public interface ExampleMapper {
    ExampleDto entityToDto(ExampleEntity exampleDto);
    ExampleEntity dtoToEntity(ExampleDto exampleDto);
}

 

테스트

@RestController
@RequestMapping("api/example")
public class ExampleController {

    private ExampleMapper exampleMapper;

    public ExampleController() {
        this.exampleMapper = Mappers.getMapper(ExampleMapper.class);
    }

    @GetMapping(path = "")
    public void getTest(){

        // dto -> entity
        ExampleDto exampleDto = ExampleDto.builder()
                .name("hello")
                .description01("설명1")
                .description02("설명2")
                .build();
        System.out.println("전 " + exampleDto);
        ExampleEntity exampleEntity = exampleMapper.dtoToEntity(exampleDto);
        System.out.println("후 " + exampleEntity);

        // entity -> dto
        ExampleEntity exampleEntity2 = ExampleEntity.builder()
                .name("hello2")
                .description01("설명21")
                .description02("설명22")
                .build();
        System.out.println("전 " + exampleEntity2);
        ExampleDto exampleDto2 = exampleMapper.entityToDto(exampleEntity2);
        System.out.println("후 " + exampleDto2);
    }
}

잘 작동합니다.

 

 

설명을 추가하자면

ObjectMapper는 내부에서 아래와 같은 클래스를 만들어줍니다.

 

public class ExampleMapperImpl implements ExampleMapper{
    @Override
    public ExampleDto entityToDto(ExampleEntity exampleEntity){
        if(exampleEntity == null){
            return null;
        }

        ExampleDto exampleDto = new ExampleDto();
        exampleDto.setName(exampleEntity.getName());
        exampleDto.setDescription01(exampleEntity.getDescription01());
        exampleDto.setDescription02(exampleEntity.getDescription02());
        return exampleDto;
    }

    @Override
    public ExampleEntity dtoToEntity(ExampleDto exampleDto){
        if(exampleDto == null){
            return null;
        }

        ExampleEntity exampleEntity = new ExampleEntity();
        exampleEntity.setName(exampleDto.getName());
        exampleEntity.setDescription01(exampleDto.getDescription01());
        exampleEntity.setDescription02(exampleDto.getDescription02());
        return exampleEntity;
    }
}

 

결론

 

오늘 알아가야 하는 한 가지는

MapStruct가 빠르고 Stateless, Thread-safe하니까 자주 애용하자 :)

 


참조 및 인용

https://mapstruct.org/documentation/stable/reference/html/#Preface

 

MapStruct 1.4.2.Final Reference Guide

If set to true, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, also showWarnings needs to be added due to a problem in the maven-compiler-plugin configuration.

mapstruct.org

 

 

 


블로그 추천 포스트

https://codemasterkimc.tistory.com/50

 

300년차 개발자의 좋은 코드 5계명 (Clean Code)

이번 글을 통해 배워갈 내용  좋은 코드(Clean Code)를 작성하기 위해 개발자로서 생각해볼 5가지 요소를 알아보겠습니다. 개요 좋은 코드란 무엇일까요? 저는 자원이 한정적인 컴퓨터 세상에서 좋

codemasterkimc.tistory.com

 

 

오늘도 즐거운 코딩 하시길 바랍니다 ~ :)

 

 

728x90
반응형