본문 바로가기
Java, Kotlin, Spring

[Java/Spring] (3) MapStruct - Mapping 필드 정의하기 2

by 댕댕미냉 2023. 1. 13.

mapstruct

 

Mapping 필드 정의하기 2

이번 포스트에서는 지난 포스트의 5.Mapping에 관련된 내용을 이어서 작성하고 있습니다. 이전의 내용이 궁금하다면 이전 게시글들을 참고하시길 바랍니다. MapStruct에 관한 게시글은 다음 게시글까지 작성 후 마무리할 예정입니다.

 

 

 

5. Mapping

지난 포스트에서는 Source에서 매핑될 필드를 무시하는 방법, 여러 Source를 조합하여 target을 만드는 방법, 그리고 source 내부의 객체를 target에 풀어서 적용하는 방법에 대해 작성하였습니다. 이어서, 이번에는 defaultValue, constant를 적용하는 방법과 expression을 활용하는 방법에 대해 서술할 예정입니다.

Source와 Target의 정의

source : 매핑 될 객체, 값을 가져오는 객체, getter가 필요합니다.
target : 매핑 할 객체, 값을 넣어주는 객체, builder 또는 생성자 + setter가 필요합니다.

 

 

5.3. DefaultValue & Constant

MapStruct에서는 매핑을 할 때, defaultValue 또는 constant를 활용하여 source의 값이 null일때 특정 값을 지정하거나, 항상 같은 값을 지정할 수 있습니다.

 

@Mapper(uses = StringListMapper.class)
public interface SourceTargetMapper {

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

    @Mapping(target = "stringProperty", source = "stringProp", defaultValue = "undefined")
    @Mapping(target = "longProperty", source = "longProp", defaultValue = "-1")
    @Mapping(target = "stringConstant", constant = "Constant Value")
    @Mapping(target = "integerConstant", constant = "14")
    @Mapping(target = "longWrapperConstant", constant = "3001")
    @Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014")
    @Mapping(target = "stringListConstants", constant = "jack-jill-tom")
    Target sourceToTarget(Source s);
}
DefaultValue & Constant 차이

DefaultValue : Target Property에 적용될 값이 null인 경우, DefaultValue에 지정된 값을 넣어서 매핑합니다.
Constant : Target Property에 일정한 값을 매핑하고 싶은 경우, constant를 통해 해당 property에 일정한 값을 매핑할 수 있습니다.

 

DefaultValue의 경우 source의 값이 null일때만 defaultValue를 활용하므로 source와 target을 전부 표기해주어야 하며, Constant의 경우 constant의 값을 항상 적용하는 것이므로 target만 표기합니다.

 

 

5.4. Expression & DefaultExpression

Expression과 DefaultExpression은 target에 값을 적용하고자 할 때, 특정 로직이 필요한 경우에 사용합니다. Source에서 Target으로 값을 매핑할 때 특정 메서드 또는 로직을 통해 변경시킨 값을 저장하고자 한다면, expression을 통해 쉽게 적용할 수 있습니다. 단, expression안에서 특정 패키지 내의 메서드를 사용한다면 패키지 이름을 전부 적거나 Mapper에 import 해주는 과정이 필요합니다.

 

// 전체 패키지 이름을 적는 경우
@Mapper
public interface SourceTargetMapper {

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

    @Mapping(target = "timeAndFormat",
         expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}


// imports를 통해 해결하는 경우
imports org.sample.TimeAndFormat;

@Mapper( imports = TimeAndFormat.class )
public interface SourceTargetMapper {

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

    @Mapping(target = "timeAndFormat",
         expression = "java( new TimeAndFormat( s.getTime(), s.getFormat() ) )")
    Target sourceToTarget(Source s);
}

 

 

5.5. Mapping Custom Method

매핑을 하다 보면, source에서 target으로 값을 넘길 때 여러 로직을 필요로 하는 경우들이 있습니다. 이런 경우 위애서 언급한 expression을 활용해도 되지만, 사용해야 하는 로직이 많은 경우 직접 커스텀 메서드를 만들어서 매핑을 할 수 있게끔 처리할 수 있습니다. 만약 인터페이스로 mapper를 만들었다면, default 메서드를 활용해서 커스텀 메서드를 만들면 됩니다. 

 

@Mapper
public interface CarMapper {

    @Mapping(...)
    ...
    CarDto carToCarDto(Car car);

    default PersonDto personToPersonDto(Person person) {
        //hand-written mapping logic
    }
}

@Mapper
public abstract class CarMapper {

    @Mapping(...)
    ...
    public abstract CarDto carToCarDto(Car car);

    public PersonDto personToPersonDto(Person person) {
        //hand-written mapping logic
    }
}

 

 

이렇게 커스텀 메서드를 만들고 나면, MapStruct가 Mapper를 생성할 때 메서드의 인자와 리턴타입이 일치하는 경우에 만들어놓은 커스텀 메서드를 활용할 수 있습니다. 구체적으로 어떤 메서드를 활용할지 지정할 수 있는 방법도 있는데, 이 방법은 다음 게시글에서 작성될 예정입니다.

 

 

 

 

2023.01.07 - [Spring] - [Java/Spring] (1) MapStruct를 활용해서 손쉽게 매핑하기

2023.01.08 - [Spring] - [Java/Spring] (2) MapStruct - Mapping 필드 정의하기

2023.01.13 - [Spring] - [Java/Spring] (3) MapStruct - Mapping 필드 정의하기 2

2023.01.13 - [Spring] - [Java/Spring] (4) MapStruct - Mapper 세부 설정