MapStruct란?

sue·2024년 12월 18일

Spring

목록 보기
3/3

MapStruct는 Java 애플리케이션에서 객체 간 매핑을 간단하고 효율적으로 수행하기 위해 사용되는 애너테이션 기반 코드 생성 라이브러리입니다.

런타임 리플렉션 대신 컴파일 타임에 매핑 코드를 자동으로 생성하므로 성능이 뛰어나고 타입 안정성이 보장됩니다.


MapStruct의 주요 특징

  1. 컴파일 타임 코드 생성
    • 런타임 리플렉션을 사용하지 않고, 컴파일 타임에 매핑 코드를 생성합니다.
    • 성능이 뛰어나고 오류를 컴파일 시점에 잡아낼 수 있습니다.
  2. 자동 필드 매핑
    • 동일한 필드 이름과 타입을 가진 객체 간 자동으로 매핑됩니다.
  3. 커스텀 매핑 지원
    • 필드 이름이 다를 때 @Mapping 애너테이션을 통해 명시적으로 매핑을 지정할 수 있습니다.
  4. 불변 객체 지원
    • DTO나 Record와 같은 불변 객체에 대한 매핑을 지원합니다.
  5. 중첩 매핑 및 컬렉션 매핑
    • 중첩된 객체나 컬렉션 타입의 매핑도 쉽게 처리할 수 있습니다.

MapStruct 설정하기

1. 의존성 추가

Maven을 사용하는 경우 pom.xml에 추가합니다.

xml
코드 복사
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct-processor</artifactId>
        <version>1.5.5.Final</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

2. 기본 사용법

MapStruct를 사용해 Entity ↔ DTO 매핑을 구현하는 예시입니다.

Entity

package entity;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class UserEntity {
    private Long id;
    private String username;
    private String email;
}

DTO

package dto;

public record UserDto(Long id, String username, String email) {}

Mapper 인터페이스

package mapper;

import dto.UserDto;
import entity.UserEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    // Entity -> DTO
    UserDto toDto(UserEntity userEntity);

    // DTO -> Entity
    UserEntity toEntity(UserDto userDto);
}

사용 예시

import dto.UserDto;
import entity.UserEntity;
import mapper.UserMapper;

public class Main {
    public static void main(String[] args) {
        UserEntity entity = new UserEntity(1L, "JohnDoe", "john@example.com");

        // Entity -> DTO
        UserDto dto = UserMapper.INSTANCE.toDto(entity);
        System.out.println(dto);

        // DTO -> Entity
        UserEntity newEntity = UserMapper.INSTANCE.toEntity(dto);
        System.out.println(newEntity.getUsername());
    }
}

3. 커스텀 매핑

필드 이름이 다른 경우 @Mapping 애너테이션을 사용합니다.

package mapper;

import dto.UserDto;
import entity.UserEntity;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    @Mapping(source = "emailAddress", target = "email")
    UserDto toDto(UserEntity userEntity);
}

4. 중첩 객체 매핑

중첩된 객체도 자동으로 매핑됩니다.

class Address {
    private String street;
    private String city;
}

class UserEntity {
    private Long id;
    private String username;
    private Address address;
}

class UserDto {
    private Long id;
    private String username;
    private String street;
    private String city;
}

Mapper 예시:

@Mapper
public interface UserMapper {
    @Mapping(source = "address.street", target = "street")
    @Mapping(source = "address.city", target = "city")
    UserDto toDto(UserEntity userEntity);
}

5. 컬렉션 매핑

리스트나 맵 같은 컬렉션 타입도 매핑할 수 있습니다.

@Mapper
public interface UserMapper {
    List<UserDto> toDtoList(List<UserEntity> userEntities);
}

6. 장단점

장점

  • 성능: 컴파일 타임에 코드를 생성하므로 빠릅니다.
  • 타입 안전성: 컴파일 시점에 매핑 오류를 잡아낼 수 있습니다.
  • 간결함: 애너테이션만으로 자동 매핑 코드를 생성합니다.
  • 유연성: 커스텀 매핑, 중첩 매핑, 컬렉션 매핑 등이 가능합니다.

단점

  • DTO마다 Mapper 인터페이스를 생성해야 합니다.
  • 초기 설정과 학습이 필요합니다.
  • 필드 매핑이 매우 복잡할 경우 수동 코드가 필요할 수 있습니다.

7. 결론

MapStruct는 객체 매핑을 위한 가장 효율적이고 성능이 뛰어난 라이브러리입니다.

런타임 리플렉션 없이 컴파일 타임에 코드를 생성하므로 성능 저하가 없고 타입 안전성을 보장합니다.

profile
All is well ! 🔥

0개의 댓글