본문 바로가기
Spring

DTO 변환하기 귀찮은 사람들 다모여라~ @MapStruct로 객체 변환하기!

by 아리❣️ 2023. 4. 23.

계층간에 쓸 객체는 분리해야겠고.... 매핑 메서드 만드는건 너무 귀찮고...

필드 하나 바뀔때마다 계속 수정해줘야 하는건 더 귀찮다....

 

출처 : 대학내일

 

그냥 대충 객체 하나로 싹다 하면 안되나? 라고 생각하는 사람들 다모여라!

MapStruct가 해결해줄터이니~

초간단 MapStruct 사용방법 가보자구👊

 

MapStruct란?

Java 객체간의 데이터를 매핑해주는 코드 생성기이다.

 

 

MapStruct의 특징

  • 컴파일 시점에 코드를 생성한다.
  • 속도가 빠르다.
  • Lombok의 getter, setter, builder등을 이용하여 생성되므로, Lombok에 의존성이 추가되어야 한다.

 

 

초간단 사용법

  1. 매핑을 위한 interface를 생성한다.
  2. (Spring에서 사용할거라면) 빈으로 만들어 사용할 수 있도록 @Mapper어노테이션을 이용한다.
  3. 매핑을 진행할 메서드를 정의한다.
@Mapper(componentModel = "spring")
public interface Mapper {

    // source -> target
    TargetObject toTarget(final SourceObject source);

}

 

 

@Mapping을 통해 커스터마이징 하기

Mapping 어노테이션을 붙이면, 자동으로 구현체가 생성된다. 이를 통해 여러 커스터마이징하여 사용할 수 있다. 해당 어노테이션을 source와 target을 통해 어떤 필드에 사용할 것인지 명시해야 한다.

  • 필드 이름이 다른 경우 매칭하기
    • @Mapping(target="target.targetA", source="source.sourceA")
  • 특정필드 무시하기
    • @Mapping(target="target.a", source="source.a", ignore=true)
  • 기본값 지정하기
    • @Mapping(target="target.A", source="source.A", defaultValue="AAA")
  • 간단한 expression 주입하기
    • @Mapping(target=”target.A”, source="source.A", defaultExpression="java(원하는작업)")
    • 컴파일 해봐야 문법 오류를 확인 할 수 있음에 주의!
    • 개인적으로는 읽기도 어려우니 메서드로 작성하는 것을 추천한다. 메서드로 작성하는 법은 하단 참고!

 

 

매핑 메서드를 직접 작성하여 매핑되도록 하기

 

내가 원하는 작업을 직접 작성하고 싶은 경우, 메서드를 직접 만들 수 있다.

public interface Mapper {

    TargetObject toTarget(final SourceObject source);

    // source안에 String타입 필드를 target의 String 타입 필드로 바꿔준다.
    String customMethod(final String source){
        // 어쩌구 저쩌구 내가 하고싶은 작업
        return null;
    }

}

 

만약 특정 필드에서 특정 메서드를 사용하도록 지정하고싶다면?

-> @Mapping에 qualifiedByNamed 파라미터를 통해 원하는 메서드를 주입할 수 있다.

이 방법을 이용하면 같은 기능을 하는 여러 메서드를 만들어 놓고, 상황에 따라 바꿔가며 사용하는 것이 가능하다.

public interface Mapper {

    // qualifiedByName 값만 바꾸면 원하는 대로 메서드를 주입할 수 있다.
    @Mapping(target="target.A", source="source.A", qualifiedByName="customMethod1")
    TargetObject toTarget(final SourceObject source);

    @Named("customMethod1")
    String customMethod1(final String source){
        // 어쩌구 저쩌구 내가 하고싶은 작업
        return null;
    }

    @Named("customMethod2")
    String customMethod2(final String source){
        // 어쩌구 저쩌구 내가 하고싶은 작업
        return null;
    }

}

 

 

그냥 내가 다 작성하기

코드의 전체적인 통일성 때문에 mapper 인터페이스는 쓰고싶은데.. 자동화고 뭐고 그냥 내가 다 만들고싶다면?

interface에서 default 키워드를 통해 메서드 작성해버리기!

public interface Mapper {

    default TargetObject toTarget(final SourceObject source) {
        // 어쩌구 저쩌구 내가 하고싶은 작업
        return null; 
    }

}

 

 

정상적으로 매핑되지 않았을 경우 어떻게 대응할지 커스터마이징 하기

Mapper 어노테이션의 unmmapedTargetPolicy 파라미터를 이용하면 target이 정상적으로 매핑되지 않은 경우 어떻게 대응할지 설정할 수 있다.

사용예시 - @Mapper(unmmapedTargetPolicy = ReportingPolicy.ERROR)

  • ERROR
    • 컴파일 시점에 ( 매핑코드가 생성되는 시점에 ) 예외가 발생한다.
  • WARN
    • warn 로그만 찍힌다.
  • IGNORE
    • 무시한다.