MapStruct 는 Java Bean Mapper 라이브러리다.
DTO ↔ Entity 같은 객체 간 변환 코드를 자동으로 생성해주는 도구이다. 구현하다 보면 매핑할 일이 많은데 간단하게 구현할 수 있게 도와준다.
userDto.setId(userEntity.getId());
userDto.setName(userEntity.getName());
userDto.setEmail(userEntity.getEmail());
필드가 많아지면 매번 이렇게 매핑 코드를 쓰는 게 엄청 귀찮고 실수도 많이 나온다. MapStruct 는 이런 매핑을 자동으로 만들어 주는 도움을 준다.
자동 코드 생성
반복되는 setter/getter 매핑 코드를 줄일 수 있다.
우리가 직접 안 써도 되고 MapStruct 가 빌드 타임에 컴파일러가 이해할 수 있는 Java 코드로 변환 코드를 만들어 준다.
컴파일 타임 체크
매핑할 필드명이 잘못되면 컴파일 시점에 에러를 내준다.
(ModelMapper 같은 라이브러리는 런타임에 매핑 실패를 알 수 있는데 MapStruct 는 빌드할 때 잡아줘서 더 안전하다.
커스텀 매핑 가능
매핑 시키는 엔티티들은 대부분 필드명이 같은데 필드명이 다른 경우는 @Mapping 을 써서 직접 선언해 줄 수도 있다.
@Mapping(target = "status", qualifiedByName = "status")
@Mapping(target = "remainingCount", source = "bulkPassEntity.count")
@Named("status")
default PassStatus status(BulkPassStatus status) {
return PassStatus.READY;
}
public interface PassModelMapper {
PassModelMapper INSTANCE = Mappers.getMapper(PassModelMapper.class);
}
interface PassModelMapper 만 작성해서 사용하고 있지만 실제적으로는 컴파일 시점에 MapStruct 가 내부에서 자동으로 구현 클래스를 만들어주고 있다. 이름은 보통 PassModelMapperImpl 로 생성된다. 안에 toPassEntity() 같은 메서드의 실제 변환 로직이 들어가고 Mappers.getMapper(PassModelMapper.class)는 그 자동으로 생성된 구현체를 찾아서 리턴해준다.
INSTANCE 는 사실 PassModelMapperImpl 객체를 가지고 있다. 우리가 따로 new PassModelMapperImpl() 해서 만들 필요 없이 이 한 줄로 PassModelMapper 를 그냥 쓸 수 있고 toPassEntity(어쩌구저쩌구) 구현체에 있는 변환 로직을 바로 사용하는게 가능한거다.
PassEntity passEntity = PassModelMapper.INSTANCE.toPassEntity(bulkPassEntity, userId);