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://mapstruct.org/faq/

 

Frequently Asked Questions (FAQ) – MapStruct

The strategies were developed over time and hence the naming / behavior deserves attention in future versions of MapStruct to getter better allignment. This would introduce backward incompatibillties, so we cannot not do this in the 1.x versions of MapStru

mapstruct.org

https://medium.com/uphill-engineering-design/deep-dive-into-mapstruct-spring-7ddd8dac3d6d

 

Deep dive into Mapstruct @ Spring

How to take advantage of Mapstruct to greatly reduce the amount of boilerplate code that would regularly be written by hand.

medium.com

 

 

+ Recent posts