infinity : 무한한 성장가능성

MapStruct 에 대해 알아보자 본문

Develop/💜Java

MapStruct 에 대해 알아보자

인피니 2025. 1. 19. 20:05
 

ModelMapper 에 대해 알아보자

modelMapper을 알아보게 된 배경에 대해 설명하자면 어느 날 주말에 갑자기 잘 돌아가던 배치에서 실패메시지가 왔다.해당 부분에 변경사항이 없을 텐데 왜 실패가 되었지? 싶어 로그를 확인해 보

infinitecoding.tistory.com

MapStruct에 대해 알아보는 이유는 윗글에 나와있습니다.

이 글을 읽전에 위 글을 읽고 오는 것을 추천드립니다. 

 

🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️MapStruct 알아보기 시작합니다. 🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️🏃‍♀️

 

 

MapStruct 란?


Java 기반의 매핑 프레임워크로 객체 간의 매필을 간단하고 성능 좋게 처리할 수 있다.

Spring Framework 와 함께 사용하면 편리하다. 

 

 

MapStruct  사용법


1. 의존성 추가

 

maven

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.3.Final</version> <!-- 최신 버전 확인 -->
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.3.Final</version>
    <scope>provided</scope>
</dependency>

 

gradle

implementation 'org.mapstruct:mapstruct:1.5.3.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'

 

 

2. 매핑 대상 클래스 생성 

public class UserDto {
    private String name;
    private int age;
}
public class UserEntity {
    private String name;
    private int age;

    public UserEntity(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

(* 위 dto 와 entity 클래스는 모두 getter와 setter 메서드가 정의되어있어야 합니다.)

 

3. 매퍼 생성

package com.example.mapper;

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

@Mapper
public interface UserMapper {

    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    UserDto toDto(UserEntity entity);

    UserEntity toEntity(UserDto dto);
}

 

매퍼를 생성하는 코드를 살펴보자

 

Mpaaers.getMapper(UserMapper.class) 

위 코드를 통해 MapStruct 가 컴파일 시점에 UserMapper 인터페이스를 기반으로 구현체 클래스를 생성한다.

따라서 위 코드를 호출하면 UserMapper 의 구현체의 싱글턴 인스턴스를 반환하게 됩니다. 

 

INSTANCE

매퍼 객체를 싱글턴으로 사용하도록 정의한 필드

인터페이스에 필드를 선언하면 해당 필드는 암묵적으로 public static final로 선언됨

 

toDto & toEntity 메서드

 

toDto & toentity 메서드는 관례적으로 사용하는 메서드 이름으로 다른이름으로 사용해도 무방합니다.

입력타입과 반환타입을 Mapstruct 가 확인해 그에 맞는 구현체를 자동으로 생성해줍니다. 

 

@Mapper 어노테이션

해당 어노테이션은 MapStruct 에게 해당 인터페이스가 매퍼 인터페이스임을 알려줍니다. 

 

주요 속성

속성 설명
componentModel 생성된 매퍼를 의존성주입(DI) 컨테이너에 등록하는 방법 (기본값은 default)
uses 다른 매퍼나 헬퍼 클래스를 참조할 때 사용
unmappedTargetPolicy 매핑되지 않은 필드에 대한 정책 설정 (IGNORE, WARN, ERROR)

 

 

사용해보기

package com.example.mapstruct;

import com.example.dto.UserDto;
import com.example.entity.UserEntity;
import com.example.mapper.UserMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MapstructApplication {

    public static void main(String[] args) {
        UserEntity userEntity = new UserEntity("John", 25);

        //Entity -> Dto
        UserDto userDto = UserMapper.INSTANCE.toDto(userEntity);
    }

}

구현체도 자동으로 생성해 주고, 매우 간편하게 사용가능한 것을 볼 수 있습니다. 

위에서 Spring Framework와 함께 사용하면 편리하다고 했었는데 어떻게 스프링과 통합하여 사용할 수 있는지 알아보겠습니다.

 

Spring과 통합하기

@Mapper을 spring과 통합하려면 componentModel = "spring"으로 설정하면 됩니다.

package com.example.mapper;

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

@Mapper(componentModel = "spring")
public interface UserMapper {
    UserDto toDto(UserEntity entity);

    UserEntity toEntity(UserDto dto);
}

이렇게 설정하면 MapStruct 가 생성한 구현체가 Spring Bean으로 등록되어 의존성 주입으로 사용할 수 있게 됩니다. 

 

package com.example.service;

import com.example.dto.UserDto;
import com.example.entity.UserEntity;
import com.example.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserMapper userMapper;

    public UserDto convertToDto(UserEntity entity) {
        return userMapper.toDto(entity);
    }
}

위 코드처럼 빈으로 등록되어 있기 때문에 의존성 주입으로 다른 서비스나, 컨트롤러단에서 쉽게 사용가능합니다. 

 

간단하게 MapStruct를 사용하는 방법에 대해 알아보았습니다.

맨 처음 MapStruct 를 알게 된 이유가 ModelMapper이었기 때문에 두 개의 차이를 비교해 보면서 이 글을 마치도록 하겠습니다.

 

ModelMapper와 ModelStruct 비교


구분 ModelMapper MapStruct
매핑방식 런타임(Reflection 기반) 컴파일 시점(코드 생성기반)
성능 상대적으로 느림 (매번 동적으로 매핑필드를 계산하기 때문) 매우 빠름 ( 사전에 컴파일된 매핑 코드를 사용)
구현방식 런타임에 동적으로 매핑 코드 생성  컴파일 시점에 매핑 코드를 생성 
코드 가독성 매핑 코드가 자동화되어 간결하지만 디버깅이 어려움  매핑 코드가 명시적으로 생성되어 가독성 및 디버깅이 용이함 
Spring 통합 축라 설정 없이 바로 사용가능  @Mapper(componentModel = "spring")
커스텀 매핑  커스텀 매핑이 비교적 복잡  애노테이션과 메서드로 간단히 커스텀매핑 가능

 

 

글에 잘못된 부분 혹은 개선해야할 점이 있으면 편하게 댓글 남겨주세요. 

 

'Develop > 💜Java' 카테고리의 다른 글

ModelMapper 에 대해 알아보자  (0) 2025.01.05
자바 제네릭 완전정복 (2)  (0) 2024.02.18
자바 제네릭 완전정복 (1)  (1) 2024.01.21