[Spring] MapStruct란?

김진회·2022년 11월 24일
0

jpa

목록 보기
4/5
post-custom-banner

1. MapStruct란?

DTO, Entity간의 매핑을 간편하게 할 수 있도록 지원해주는 라이브러리다.
@Mapper를 사용하고 @Mapping으로 컬럼에 대한 추가적인 설정을 해주면 컴파일 시, MapperImpl을 생성해준다.

  • 장점
    • 컴파일 시 오류를 확인할 수 있다.
    • 생산성이 향상된다.
    • 생성된 매핑 코드를 눈으로 직접 확인할 수 있다.
    • 리플렉션(Reflection)을 사용하지 않아 매핑 속도가 빠르다.
      리플렉션: 구체적인 클래스 타입을 알지 못해도, 그 클랙스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API

2. 기존의 Mapping 방법

MapStruct를 자세히 알아보기 전에 기존의 Mapping 방법을 알아보자.
기존 DTO와 Entity간의 매핑 방법은 객체 생성 후, setter사용, @Builder사용, ModelMapper가 있다. 본인은 그 중 @Builder를 이용했다.

//DTO/Entity에 @Builder 선언 후,

RecordDto.builder().
	.id(Record.getId())
    .name(Record.getName())
    .myTreeId(Record.getMyItemId())
    .build();

위 방법은 필드가 많아진다면 꽤나 코드가 길어지고 그만큼 실수할 가능성이 생긴다.


3. MapStruct를 이용한 방법

1) 환경설정

Gradle에 mapstruct에 대한 dependencies를 설정한다

dependencies {
    // lombok
    implementation 'org.projectlombok:lombok:1.18.22'
    annotationProcessor 'org.projectlombok:lombok:1.18.22'
    annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0' // v1.18.16+ 부터

    // mapstruct
    implementation 'org.mapstruct:mapstruct:1.4.2.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}

2) EntityMapper 인터페이스 구현

Generic을 이용해서 MapStruct를 위한 인터페이스를 구현한다.
본인은 보통 이런 파일은 /global/common/mapper 폴더를 생성해서 여기에 작성한다.

public interface EntityMapper<D, E> {
    E toEntity(final D dto);
    D toDto(final E entity);
}

3) Mapper 작성

Product에 대한 Mapper을 작성해보겠다.
예시) RecordDto는 필드로 id, name, itemId, myItemid을 갖는다. MyItem은 itemId를 필드로 갖는다.

@Mapper
public interface RecordMapper extends EntityMapper<RecordDto, Record> {
    RecordMapper mapper = Mappers.getMapper(RecordMapper.class);

    @Override
    @Mapping(target = "userId", ignore = true)
    @Mapping(source = "myItem.item.id", target = "itemId")
    @Mapping(source = "myItem.id", target = "myItemId")
    RecordDto toDto(final Record entity);

    @Override
    @Mapping(source = "itemId", target = "myItem.item.id")
    @Mapping(source = "myItemId", target = "myItem.id")
    Record toEntity(final RecordDto dto);
}
  • 작성 방법
    • @Mapper: 해당 인터페이스의 구현체를 생성한다.
    • @Mapping: 매핑 과정에서 특정 필드를 ignore하거나 따로 설정한다.
    • 정책
      • unmappedSourcePolicy
        • IGNORE, WARN, ERROR
        • 매핑시 Sourece.aFiled가 사용되지 않는다면 컴파일 오류
        • ERROR로 설정시 매핑되지 않았다면 컴파일 오류가 발생
      • unmappedTargetPolicy
        • IGNORE, WARN, ERROR
        • 매핑시 Target.aFiled가 사용되지 않는다면 컴파일 오류
      • typeConversionPolicy
        • IGNORE, WARN, ERROR
        • 타입 변환시 유실이 발생할 수 있을 때 정책
        • long -> int로 값을 넘길 때 유실이 발생, 이런 경우에 정책을 설정할 수 있다.
    • 전략
      • nullValueMappingStrategy
        • RETURN_NULL(deafult), RETURN_DEFAULT
        • Source가 null일 때 정책이다.
      • nullValuePropertyMappingStrategy
        • SET_TO_NULL(default), SET_TO_DEFAULT, IGNORE
        • Source의 필드가 null일 때 정책

4) 컴파일 및 사용

컴파일 시, build폴더에 MapperImpl이 생성된다. ServiceImpl에서 해당 MapperImpl을 사용하면 된다.
여기서 @Mapping 설정에 따라 Entity->DTO 변환 시, userId는 null로 들어간다.
* userId와 같이 보안에 신경써야 하는 필드는 ignore설정을 해주는 것이 좋다.

//DTO(recordDto) <-> Entity(record)
RecordDto recordDto= RecordMapper.mapper.toDto(record);
Record record= RecordMapper.mapper.toEntity(recordDto);

4. 주의사항

정책을 ERROR로 설정하지 않았으면 컴파일 시, 에러코드가 출력되지만 에러가 발생하는 필드를 제외하고 MapperImpl이 생성된다. 따라서 후에 MapperImpl이 존재하기 때문에 프로그램이 중단되지 않고 그대로 작동된다. 이 MapperImpl은 정상적인 작동을 하는 클래스가 아니니 이를 인지하고 있도록 하자

이를 방지하기 위해 정책을 Error로 설정해 오류가 있으면 파일 생성을 중단시킬 수 있다.


참조

https://meetup.toast.com/posts/213

https://joojimin.tistory.com/19

profile
SSAFY 7기. HMG. 협업, 소통, 사용자중심
post-custom-banner

1개의 댓글

comment-user-thumbnail
2024년 8월 13일

In the defender position, Como brought in quality defenders in Raphaël Varane and Alberto Moreno. Varane was recruited from Manchester United, while Moreno came from Villarreal. They arrived on free transfers.
https://www.nobartv.co.id/berita-terkini
https://en.nobartv.co.id/berita-terkini
https://ko.nobartv.co.id/berita-terkini
https://ja.nobartv.co.id/berita-terkini
https://ar.nobartv.co.id/berita-terkini
Varane's champion mentality is certainly not in doubt, because he was with the French National Team when they won the 2018 World Cup. When he was still with Real Madrid, Varane was even able to collect 18 titles, including 4 Champions League (UCL) trophies. While Moreno has 1 UCL trophy with Liverpool, and 2 Europa Leagues with Sevilla and Villarreal.
https://hi.nobartv.co.id/berita-terkini
https://ru.nobartv.co.id/berita-terkini
https://es.nobartv.co.id/berita-terkini
https://th.nobartv.co.id/berita-terkini
https://fr.nobartv.co.id/berita-terkini
Como also brought in Andrea Dossena from Cagliari. The three of them complete the back line alongside Marco Sala, Edoardo Goldaniga, Felipe Jack, Peter Kováčik, Tommaso Cassandro and Federico Barba.

답글 달기