Programming/Spring

MapStruct & Lombok 적용

사랑우주인 2022. 5. 4. 11:04

MapStruct

- Dto를 Entity로 매핑(반대도 가능)해주는 라이브러리다.

- 리플렉션이 아닌 직접 메소드를 호출하는 방식으로 동작하여 속도가 빠르다.  


Set up

...
<properties>
        <java.version>11</java.version>
        <org.mapstruct.version>1.3.1.Final</org.mapstruct.version>
        <org.projectlombok.version>1.18.12</org.projectlombok.version>
    </properties>
...
<dependencies>
     <!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.version}</version>
            <scope>provided</scope>
        </dependency>
</dependencies>
...
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>        <!-- java 버전을 따름-->
                    <source>11</source>
                    <target>11</target>
                    <annotationProcessorPaths>          <!-- mapstruct 를 호출시 lombok 과 충돌 발생. 그래서 mapstruct와 lombok 에 대한 path 추가(mapstruct가 항상 lombok보다 우선 -->
                        <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>
                    </annotationProcessorPaths>
                    <compilerArgs>          <!-- 아래와 같이 의존성을 추가하면 매번 mapper에 @Mapper(componentModel = "spring")를 지정하지 안아도 된다. -->
                        <compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
                    </compilerArgs>
                </configuration>
            </plugin>


        </plugins>
    </build>
...

주의!

lombok mapstruct 같이 사용할 경우, path 지정하지 않으면 충돌이 발생한다annotationProcessorPaths  이용해 path 지정한다.


<Entity>

@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Car {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false)
  private Long id;

  @Column(name = "price")
  private int price;

  @Enumerated(EnumType.STRING)
  @Column(name = "color")
  private Color color;

  @Column(name = "name")
  private String name;

}

 

<Dto>

@Getter
@Builder
public static class CarWebResponse{
  private Long id;
  private Color color;
  private String name;


  public static CarWebResponse of(Car car){
    return CarMapper.INSTANCE.toCarWebResponse(car);
  }

 

<Interface>

@Mapper
public interface CarMapper {
  CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);

  // Create
  // - Entity -> WebDto
  @Mapping(target = "id", source = "car.id")
  CarWebDto.CarWebResponse toCarWebResponse(Car car);

}

- @Mapper 가 붙은 인터페이스는 MapStruct Code Generator가 해당 인터페이스의 구현체를 생성해준다.

- 구현체 생성 시 soruce가 되는 클래스와 target이 되는 클래스의 속성명을 비교하고 자동으로 매핑 코드를 작성한다.
- 매핑될 속성명이 다를 경우 @Mapping 어노테이션을 통해 매핑정보를 맞춰준다.

 

<Implementation>

Mapper을 생성했다면 아래와 같은 구현체를 자동으로 생성해준다.

package com.tmax.cicdpractice;

import com.tmax.cicdpractice.CarWebDto.CarWebResponse;
import com.tmax.cicdpractice.CarWebDto.CarWebResponse.CarWebResponseBuilder;
import javax.annotation.processing.Generated;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2022-05-04T10:09:33+0900",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 11.0.13 (Oracle Corporation)"
)
public class CarMapperImpl implements CarMapper {

    @Override
    public CarWebResponse toCarWebResponse(Car car) {
        if ( car == null ) {
            return null;
        }

        CarWebResponseBuilder carWebResponse = CarWebResponse.builder();

        carWebResponse.id( car.getId() );
        carWebResponse.color( car.getColor() );
        carWebResponse.name( car.getName() );

        return carWebResponse.build();
    }
}

 

참고

https://ykh6242.tistory.com/entry/반복적인-DTO-변환-작업을-한-번에-정의-MapStruct-기본-정리 

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

https://iyk2h.tistory.com/171