8.0 KiB
MapStruct란?
MapStruct는 Java Bean 간의 매핑을 쉽게 해주는 코드 생성 기반 매퍼 프레임워크입니다.
DTO(Data Transfer Object)와 Entity 간의 변환을 할 때 반복되는 getter/setter 작업을 자동화해주며, 런타임이 아닌 컴파일 타임에 매핑 코드를 생성하므로 성능도 뛰어납니다.
주요 특징
- 컴파일 타임에 코드 생성 (런타임 Reflection 사용 X)
- Lombok과 잘 연동됨
- 커스터마이징 가능 (부분 매핑,
@Mapping등) - Spring과 쉽게 통합
Spring Boot에서 MapStruct 사용 예시
1. Gradle 설정
dependencies {
implementation ("org.mapstruct:mapstruct:1.6.3")
annotationProcessor ("org.mapstruct:mapstruct-processor:1.6.3")
}
tasks.withType(JavaCompile) {
options.annotationProcessorPath = configurations.annotationProcessor
}
2. DTO 및 Entity 클래스
// User.java (Entity)
@Getter @Setter
public class User {
private Long id;
private String name;
private String email;
}
// UserDto.java
@Getter @Setter
public class UserDto {
private String name;
private String email;
}
3. 매퍼 인터페이스 작성
@Mapper(componentModel = "spring") // Spring Bean으로 등록
public interface UserMapper {
UserDto toDto(User user);
User toEntity(UserDto userDto);
}
componentModel = "spring"을 설정하면 Spring의@Component로 등록되므로, 의존성 주입이 가능합니다.
4. 서비스에서 사용
@Service
@RequiredArgsConstructor
public class UserService {
private final UserMapper userMapper;
public UserDto getUserDto(User user) {
return userMapper.toDto(user);
}
}
마무리
MapStruct는 반복적인 매핑 코드를 없애고, 명시적이고 빠른 매핑을 제공하는 훌륭한 도구입니다. 특히 Spring Boot + Lombok과 함께 사용하면 생산성과 유지보수성이 크게 향상됩니다.
필요하다면 @Mapping 어노테이션을 사용해 필드명을 다르게 매핑하거나, 일부 필드만 매핑하는 커스터마이징도 가능합니다.
좋습니다! 이번에는 MapStruct의 고급 기능들을 소개해드릴게요. 실무에서 자주 쓰이는 매핑 커스터마이징 기능과 예제 중심으로 설명드릴게요.
MapStruct 고급 기능
1. @Mapping: 이름이 다른 필드 매핑
DTO와 Entity의 필드명이 다를 경우 사용합니다.
@Getter @Setter
public class User {
private Long id;
private String fullName;
}
@Getter @Setter
public class UserDto {
private String name;
}
@Mapper(componentModel = "spring")
public interface UserMapper {
@Mapping(source = "fullName", target = "name")
UserDto toDto(User user);
}
source: 원본 객체의 필드
target: 매핑될 대상 객체의 필드
2. @Mapping(target = ..., ignore = true): 특정 필드 무시
@Mapping(target = "id", ignore = true)
User toEntity(UserDto dto);
id는 DB에서 자동 생성되므로 무시할 때 자주 사용합니다.
3. @InheritInverseConfiguration: 역 매핑 정의 재사용
@Mapper(componentModel = "spring")
public interface UserMapper {
@Mapping(source = "fullName", target = "name")
UserDto toDto(User user);
@InheritInverseConfiguration
User toEntity(UserDto dto);
}
toDto에 정의된 매핑 규칙을toEntity에도 반대로 적용합니다.
4. @AfterMapping / @BeforeMapping: 매핑 전후 로직 삽입
@Mapper(componentModel = "spring")
public interface UserMapper {
UserDto toDto(User user);
@AfterMapping
default void enrichDto(@MappingTarget UserDto dto) {
dto.setName(dto.getName().toUpperCase()); // 예: 이름을 대문자로 처리
}
}
5. 중첩 객체 매핑 (Nested Mapping)
@Getter @Setter
public class User {
private Address address;
}
@Getter @Setter
public class Address {
private String city;
}
@Getter @Setter
public class UserDto {
private String city;
}
@Mapping(source = "address.city", target = "city")
UserDto toDto(User user);
중첩된 객체의 필드도
. (dot)문법으로 접근 가능합니다.
6. Collection 매핑
List<UserDto> toDtoList(List<User> users);
Set<User> toEntitySet(Set<UserDto> dtos);
List, Set, Map 같은 컬렉션도 자동 매핑됩니다.
7. Mapper 간 의존성 (다른 Mapper 사용)
@Mapper(componentModel = "spring", uses = { AddressMapper.class })
public interface UserMapper {
UserDto toDto(User user);
}
복잡한 구조에서는 하위 매퍼를 만들어 분리할 수 있어요.
정리
MapStruct 고급 기능을 사용하면 다음과 같은 작업이 쉬워집니다:
- 필드명이 다른 경우 매핑
- 무시할 필드 지정
- 매핑 재사용 (
@InheritInverseConfiguration) - 후처리 로직 삽입
- 복잡한 구조/컬렉션/다형성 처리
좋아요! 이번에는 MapStruct의 고급 기능 중에서도 실무에서 자주 사용되는 Enum 매핑, 커스텀 매핑 메서드, Builder 패턴 지원에 대해 자세히 설명드릴게요.
1. Enum 매핑
MapStruct는 기본적으로 같은 이름을 가진 Enum 상수끼리 자동으로 매핑합니다.
예시: 이름이 같은 Enum 매핑
public enum Role {
ADMIN, USER
}
public enum RoleDto {
ADMIN, USER
}
@Mapper(componentModel = "spring")
public interface UserMapper {
RoleDto toDto(Role role);
}
이름이 같다면 자동으로 매핑됩니다.
이름이 다르면@ValueMapping또는@Mapping을 사용해야 해요.
예시: 이름이 다른 Enum 매핑
public enum Role {
ADMINISTRATOR, NORMAL_USER
}
public enum RoleDto {
ADMIN, USER
}
@ValueMappings({
@ValueMapping(source = "ADMINISTRATOR", target = "ADMIN"),
@ValueMapping(source = "NORMAL_USER", target = "USER")
})
RoleDto toDto(Role role);
2. 커스텀 매핑 메서드
MapStruct는 매핑 중 호출할 사용자 정의 메서드도 지원합니다.
예시: 날짜 형식 변환
@Getter @Setter
public class User {
private LocalDateTime registeredAt;
}
@Getter @Setter
public class UserDto {
private String registeredDate;
}
@Mapper(componentModel = "spring")
public interface UserMapper {
@Mapping(source = "registeredAt", target = "registeredDate")
UserDto toDto(User user);
default String map(LocalDateTime dateTime) {
return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
}
}
MapStruct는
LocalDateTime -> String변환 시map(...)메서드를 자동으로 호출합니다.
3. Builder 패턴 지원
Builder 패턴을 사용하는 객체도 MapStruct에서 지원합니다.
Lombok의 @Builder를 쓰거나 직접 Builder 클래스를 만든 경우에도 동작합니다.
예시: Lombok + Builder
@Getter @Setter
@Builder
public class UserDto {
private String name;
private String email;
}
@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = false))
public interface UserMapper {
UserDto toDto(User user);
}
MapStruct는
@Builder가 붙은 클래스에 대해 자동으로.builder().field(...).build()를 사용해 객체를 생성합니다.
주의할 점:
@Builder(disableBuilder = true)이면 Builder 무시@Builder(disableBuilder = false)또는 생략하면 Builder 사용- 커스텀 Builder 클래스의 경우 구조가 달라지면 빌더 매핑이 안 될 수도 있으니 주의
마무리 정리
| 기능 | 설명 |
|---|---|
| Enum 매핑 | Enum 이름 자동 매핑, 다를 경우 @ValueMapping 사용 |
| 커스텀 메서드 | 복잡한 변환 로직을 메서드로 정의 가능 |
| Builder 패턴 | @Builder 객체도 매핑 가능 (자동 빌더 생성) |