Spring Framework

[MapStruct] 필드 매핑할 때 다른 Mapper 클래스의 메소드 사용하는 법 - uses, @Named

개발자 이우진 2024. 8. 7. 17:34

상황

UserDto.unlockingConstellation을 매핑할 때 UserConstellationMapper.toDto(UserConstellation)를 사용해서 매핑하려고 한다. 자동으로 생성된 코드에서는 UserDto.unlockingConstellation.constellation까지 .get()하여 의도하지 않은 SELECT가 발생하기 때문이다.

public class UserDto {
...
/**
     * 현재 해금중인 유저 별자리 상태
     */
    private UserConstellationDto unlockingConstellation;
}
@Mapper(componentModel = "spring", uses={UserConstellationMapper.class})
public interface UserMapper {
...
    // ! 이렇게 해도 UserMapperImpl에서 UserConstellationMapper를 참조하지 않는다
    @Mapping(target = "unlockingConstellation", source = "unlockingConstellation")
    UserDto toDto(User user, UserConstellation unlockingConstellation);
}

해결법

  1. UserMapper@Mapper(uses={UserConstellationMapper.class})를 추가해서 다른 Mapper 클래스를 불러오게 한다
  2. 불러올 클래스와 메소드에 @Named로 별명을 붙여 준다. 클래스에도 추가해야 한다.
  3. 매핑할 필드에서 qualifiedByName = {"클래스 별명", "메소드 별명"} 을 추가해 준다.

이렇게 하면 자동으로 생성된 UserMapperImpl에서 UserConstellationMapper 멤버 변수를 추가해서 의존성을 주입하고 userConstellationMapper.toDto()를 호출한다.

@Mapper(componentModel = "spring")
@Named("UserConstellationMapper")
public interface UserConstellationMapper {
...
    @Mapping(target = "constellation", ignore = true)
    @Named("toDto(UserConstellation)")
    UserConstellationDto toDto(UserConstellation userConstellation);
 ...
 }

@Mapper(componentModel = "spring", uses={UserConstellationMapper.class})
public interface UserMapper {
...
    @Mapping(target = "unlockingConstellation", source = "unlockingConstellation", qualifiedByName = {"UserConstellationMapper", "toDto(UserConstellation)"})
    UserDto toDto(User user, UserConstellation unlockingConstellation);
}

출처

MapStruct 공식 문서 - 5.9. Mapping method selection based on qualifiers