Mapping 필드 정의하기
지난 게시글에서는 MapStruct가 무엇인지, 그리고 Mapper는 어떻게 생성하는지에 대해 알아보았습니다. 이번 게시글에서는 Mapper 내부의 Mapping은 어떻게 해야 하는 지에 대해 작성되었습니다.
4. Mapper에서 사용되는 객체
본격적인 Mapping에 앞서, Mapping에서 사용되는 객체는 크게 2가지로 정의하며, 이는 source와 target이라고 합니다. source와 target에 대한 정의는 다음과 같습니다.
- source : 매핑 될 객체, 값을 가져오는 객체, getter가 필요합니다.
- target : 매핑 할 객체, 값을 넣어주는 객체, builder 또는 생성자 + setter가 필요합니다.
source에서 target으로 매핑을 진행할 때, source의 필드들을 getter로 가져와서 target에 매핑하게 됩니다. target에 매핑을 진행할 때는, target의 조건에 따라 MapperImpl이 매핑되는 방식이 달라지게 됩니다. target에 builder가 존재한다면 builder를 사용하여 매핑을 진행하고, 그렇지 않다면 생성자 & setter를 통해 매핑을 진행하게 됩니다.
양방향 매핑 (ex. Domain → DTO, DTO → Domain)을 하는 경우, source의 조건과 target의 조건을 양쪽에서 모두 만족해야 합니다.
4.1. target을 생성할 때 우선순위
target을 생성할 때, 생성하는 방식에는 우선순위가 존재합니다. 아래와 같은 우선순위를 통해, 먼저 만족하는 경우를 반영하여 target을 생성합니다.
- Builder가 존재하는 경우, builder를 활용하여 target을 생성합니다.
- @Default로 지정된 생성자가 존재하는 경우, 해당 생성자를 활용하여 target을 생성합니다.
- public 생성자가 존재하는 경우, 해당 생성자를 활용하여 target을 생성합니다.
- 파라미터가 없는 생성자가 존재하는 경우, 해당 생성자를 활용하여 target을 생성합니다.(NoArgsConstructor)
5. Mapping
source → target으로 매핑을 진행할 때, 동일한 필드명을 기준으로 매핑을 진행합니다. source의 필드와 target의 필드명이 다른 경우, @Mapping 어노테이션을 통해 매핑하고자 하는 필드를 직접 지정할 수 있습니다.
@Mapper
public interface CarMapper {
@Mapping(target = "manufacturer", source = "make")
@Mapping(target = "seatCount", source = "numberOfSeats")
@Mapping(target = "id", ignore = true)
CarDto carToCarDto(Car car);
@Mapping(target = "fullName", source = "name")
PersonDto personToPersonDto(Person person);
}
@Mapping의 property 중 source는 source 내부의 필드명, target은 target 내부의 필드명을 의미합니다.
5.1. 필드 무시하기
매핑 중 원래대로면 매핑이 되는 필드이지만, source의 필드가 target으로 매핑이 되는 것을 원하지 않을 수 있습니다. 또, source나 target에 매핑이 되지 않는 필드들에 대해 무시하고 싶은 경우, 다음과 같이 대응 할 수 있습니다.
- Mapping의 property 중 하나인 ignore = true 를 지정함으로써 해당 매핑 메서드에서 매핑이 되지 않게 할 수 있습니다. 단, ignore = true를 사용할 때는 target 값만 지정해야 합니다. (어떤 필드가 매핑되지 않아야 하는지를 지정, 위 코드 참고)
- Mapper 전체에서 매핑이 되지 않는 필드들을 무시하고 싶다면, @Mapper의 property인 unmappedTargetPolicy, unmappedSourcePolicy를 활용할 수 있습니다. 해당 property의 값으로 ReportingPolicy.IGNORE를 지정하면 됩니다. Source의 필드들을 무시하고 싶다면 unmappedSourcePolicy를, target의 매핑되지 않는 필드들을 무시하고 싶다면 unmappedTargetPolicy를 활용하면 됩니다.
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE,
unmappedSourcePolicy = ReportingPolicy.IGNORE)
public interface CarMapper {
CarDto carToCarDto(Car car);
}
5.2. 여러 파라미터 활용하기
MapStruct는 source → target의 과정에서 일대일 매핑 뿐 아니라 다대일 매핑도 지원합니다. 즉, 여러 source를 하나의 target에 매핑될 수 있도록 지정할 수 있습니다. source 들에서 동일한 필드명이 존재하는 경우, 매핑 중 오류가 발생합니다. 이러한 상황을 막기 위해, 동일한 필드명이 source에서 존재하는 경우 어떤 source의 필드를 매핑할 것인지 @Mapping에 명시적으로 표기해야 합니다. (필드명이 유일한 경우, 따로 지정할 필요 없습니다.)
@Mapper
public interface AddressMapper {
@Mapping(target = "description", source = "person.description")
@Mapping(target = "houseNumber", source = "address.houseNo")
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}
@Mapper
public interface AddressMapper {
@Mapping(target = "description", source = "person.description")
@Mapping(target = "houseNumber", source = "hn")
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}
5.3. Target This(.)
매핑을 하다 보면, source 안에 있는 필드 중 객체인 필드를 target에 풀어서 적용하고 싶은 상황이 있을 수 있습니다. 이런 경우를 위해, MapStruct는 Target This(.)라는 방법을 제공합니다.
@Mapper
public interface CustomerMapper {
@Mapping( target = "name", source = "record.name" )
@Mapping( target = ".", source = "record" )
@Mapping( target = ".", source = "account" )
Customer customerDtoToCustomer(CustomerDto customerDto);
}
위 예시에서, source인 customerDto의 필드 중 하나인 record는 내부에 여러 필드를 가지고 있는 객체입니다. 여기서 target = "."를 지정함으로써 record 내부의 필드들이 직접 Customer의 필드로 지정되게 됩니다.
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 세부 설정
'Java, Kotlin, Spring' 카테고리의 다른 글
[Java/Spring] Resilience4j - Circuit Breaker (1). 정의 (0) | 2023.02.11 |
---|---|
[Java/Spring] (4) MapStruct - Mapper 세부 설정 (0) | 2023.01.13 |
[Java/Spring] (3) MapStruct - Mapping 필드 정의하기 2 (0) | 2023.01.13 |
[Java/Spring] (1) MapStruct를 활용해서 손쉽게 매핑하기 (0) | 2023.01.07 |
[SpringBoot 3.0] SpringBoot 3.0 버전 업그레이드 방법 (0) | 2023.01.05 |