MapStruct를 사용하는 이유
Controller, Service, Repository 등 레이어 간 데이터를 주고받을 때나 비즈니스 로직에서, 하나의 객체를 타입이 다른 객체로 형(Type) 변환하거나 여러 객체를 다른 객체로 합치는 일은 매우 빈번한여 결국 생산성을 떨어뜨리고, 비즈니스 로직에 섞이게 되면 코드가 복잡해집니다.
이 API에는 두 Java Bean 간에 자동으로 매핑되는 기능이 포함되어 있습니다.
MapStruct를 사용하여 인터페이스만 생성하면 라이브러리는 컴파일 시간 동안 구체적인 구현을 자동으로 생성합니다.
엔티티와 클라이언트 측으로 나가는 DTO 간에 변환이 발생하는 경우가 많은데 이때 수동으로 빈 mapper를 만드는 것은 시간이 많이 걸리고, 이 부분을 MapStruct가 해결합니다.
MapStruct 라이브러리는 자동으로 빈 매퍼 클래스를 생성합니다. MapStruct라이브러리를 추가하고, @Mapper 어노테이션이 선언된 interface를 선언합니다. 구현 클래스를 생성하지 않았도 MapStruct가 가 자동생성해줍니다. mvn clean install을 실행하여 MapStruct 처리를 trigger할 수 있고, 그러면 /target/generated-sources/annotations/ 아래에 구현 클래스가 생성됩니다.
Lombok과 함께 사용하는 경우
Lombok과 MapStruct를 함께 사용하면 런타임시 에러가 발생하는 것을 확인할 수 있었습니다.
Project Lombok은 (무엇보다도) 컴파일된 빈 클래스의 AST(추상 구문 트리)에 getter와 setter를 추가하는 주석 처리기인데
AST 수정은 Java 주석 처리 API에서 예측할 수 없으므로 Lombok과 MapStruct 내에서 둘 다 함께 작동하도록 하려면 별도 작업을 해줘야합니다. 기본적으로 MapStruct는 Lombok이 enhanced-bean에 대한 매퍼 클래스를 생성하기 전에 Lombok이 모든 수정을 완료할 때까지 기다립니다. Lombok 1.18.16 이상을 사용하는 경우 Lombok과 MapStruct가 함께 작동하도록 하기 위해 lombok-mapstruct-binding을 추가해야 합니다. MapStruct 또는 Lombok의 이전 버전을 사용하는 경우 솔루션은 Lombok에서 수정할 JavaBeans와 MapStruct에서 처리할 매퍼 인터페이스를 프로젝트의 두 개의 개별 모듈에 넣는 것입니다. 그런 다음 Lombok은 첫 번째 모듈의 컴파일에서 실행되어 두 번째 모듈을 컴파일하는 동안 MapStruct가 실행될 때 빈 클래스가 완료되도록 합니다.
작업내용
mapstruct 라이브러리와 함께 lombok-mapstruct-binding을 추가하고,
아래와 같이 플러그인을 추가해주니 정상 작동 되는 것을 확인할 수 있었습니다.
<properties>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
<org.projectlombok>1.18.20</org.projectlombok>
<lombok-mapstruct-binding>0.2.0</lombok-mapstruct-binding>
</properties>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding}</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source> <!-- depending on your project -->
<target>${java.version}</target> <!-- depending on your project -->
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok}</version>
</path>
<!-- This is needed when using Lombok 1.18.16 and above -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
@Mapper(componentModel = "spring")
public interface TestMapper {
Test toTestEntity(TestForm testForm);
}
참고
https://medium.com/uphill-engineering-design/deep-dive-into-mapstruct-spring-7ddd8dac3d6d
'자바' 카테고리의 다른 글
HttpServletRequestWrapper - RequestBody에 담긴 내용을 Interceptor에서 로그로 남겨보자. (0) | 2022.06.17 |
---|---|
Static Synchronization in Java (Static과 Synchronized) (0) | 2022.03.21 |
JEP draft: Virtual Threads 가상스레드 (0) | 2022.01.03 |
JAVA 설계 원칙 : SOLID 이해 (0) | 2021.09.29 |
WebClient의 onStatus()내 코드를 TypeToken 을 활용하여 중복을 피해보자. (0) | 2021.09.27 |