DTO, Entity간의 매핑을 간편하게 할 수 있도록 지원해주는 라이브러리다.
@Mapper
를 사용하고 @Mapping
으로 컬럼에 대한 추가적인 설정을 해주면 컴파일 시, MapperImpl
을 생성해준다.
리플렉션: 구체적인 클래스 타입을 알지 못해도, 그 클랙스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API
MapStruct를 자세히 알아보기 전에 기존의 Mapping 방법을 알아보자.
기존 DTO와 Entity간의 매핑 방법은 객체 생성 후, setter사용
, @Builder사용
, ModelMapper
가 있다. 본인은 그 중 @Builder
를 이용했다.
//DTO/Entity에 @Builder 선언 후,
RecordDto.builder().
.id(Record.getId())
.name(Record.getName())
.myTreeId(Record.getMyItemId())
.build();
위 방법은 필드가 많아진다면 꽤나 코드가 길어지고 그만큼 실수할 가능성이 생긴다.
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'
}
Generic을 이용해서 MapStruct를 위한 인터페이스를 구현한다.
본인은 보통 이런 파일은 /global/common/mapper 폴더를 생성해서 여기에 작성한다.
public interface EntityMapper<D, E> {
E toEntity(final D dto);
D toDto(final E entity);
}
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);
}
ignore
하거나 따로 설정한다.컴파일 시, 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);
정책을 ERROR로 설정하지 않았으면 컴파일 시, 에러코드가 출력되지만 에러가 발생하는 필드를 제외하고 MapperImpl
이 생성된다. 따라서 후에 MapperImpl
이 존재하기 때문에 프로그램이 중단되지 않고 그대로 작동된다. 이 MapperImpl
은 정상적인 작동을 하는 클래스가 아니니 이를 인지하고 있도록 하자
이를 방지하기 위해 정책을 Error로 설정해 오류가 있으면 파일 생성을 중단시킬 수 있다.