MapStruct에서 List 등 컬렉션의 하위 객체를 무시할 수 있나요?
MapStruct는 기본적으로 컬렉션(List, Set 등)의 하위 객체 필드를 @Mapping
애노테이션의 ignore
속성을 사용하여 직접 무시할 수 없습니다. 이는 @Mapping
애노테이션이 컬렉션 자체에 적용되기 때문입니다. 하지만 대안이 없는 것은 아닙니다. 컬렉션의 요소 타입에 대한 매핑을 별도로 정의하여 원하는 필드를 무시할 수 있습니다.
예시 상황
public class Order {
private List<Item> items;
// getters and setters
}
public class Item {
private String name;
private String description;
private double price;
// getters and setters
}
public class OrderDto {
private List<ItemDto> items;
// getters and setters
}
public class ItemDto {
private String name;
private double price;
// getters and setters
}
위의 클래스에서 Item
의 description
필드를 ItemDto
로 매핑할 때 무시하고 싶다고 가정해봅시다.
해결 방법
1. 하위 객체에 대한 별도의 매퍼 생성
Item
과 ItemDto
간의 매핑을 담당하는 별도의 매퍼 인터페이스를 생성하고, 그 안에서 무시하고자 하는 필드를 지정합니다.
@Mapper
public interface ItemMapper {
@Mapping(target = "description", ignore = true)
ItemDto toDto(Item item);
}
그 다음, Order
와 OrderDto
를 매핑하는 매퍼에서 uses
속성을 통해 ItemMapper
를 사용하도록 지정합니다.
@Mapper(uses = ItemMapper.class)
public interface OrderMapper {
OrderDto toDto(Order order);
}
이렇게 하면 OrderMapper
는 ItemMapper
를 사용하여 Item
리스트를 ItemDto
리스트로 매핑하며, 그 과정에서 description
필드는 무시됩니다.
2. @Named
와 qualifiedByName
사용
별도의 매퍼를 생성하지 않고, 매퍼 내부에서 특정 메서드를 지정하여 매핑할 수도 있습니다.
@Mapper
public interface OrderMapper {
@Mapping(target = "items", qualifiedByName = "itemToItemDto")
OrderDto toDto(Order order);
@Named("itemToItemDto")
@Mapping(target = "description", ignore = true)
ItemDto itemToItemDto(Item item);
}
여기서 @Named
애노테이션을 사용하여 매핑 메서드에 이름을 부여하고, qualifiedByName
를 통해 해당 메서드를 사용하도록 지정합니다.
3. @AfterMapping
을 활용한 후처리
매핑 후에 특정 필드를 null로 설정하는 방법입니다. 다만, 이 방법은 매핑 후 추가 연산이 필요하므로 효율적이지 않을 수 있습니다.
@Mapper
public interface OrderMapper {
OrderDto toDto(Order order);
@AfterMapping
default void afterMapping(@MappingTarget OrderDto orderDto) {
if (orderDto.getItems() != null) {
for (ItemDto item : orderDto.getItems()) {
item.setDescription(null);
}
}
}
}
결론 및 대안
- 직접적인 무시 불가: MapStruct에서는 컬렉션의 하위 객체 필드를
ignore
로 직접 무시할 수 없습니다. - 별도의 매퍼 사용: 하위 객체 타입에 대한 매퍼를 별도로 정의하여 원하는 필드를 무시합니다.
- 매핑 메서드 지정:
@Named
와qualifiedByName
을 사용하여 특정 매핑 메서드를 지정합니다. - 후처리 로직 추가:
@AfterMapping
을 통해 매핑 후에 필드를 수정합니다.
이러한 방법들을 통해 원하는 대로 컬렉션의 하위 객체 필드를 무시할 수 있습니다. 가장 권장되는 방법은 별도의 매퍼를 생성하여 사용하는 것입니다. 이는 코드의 재사용성과 유지보수성을 높여줍니다.
추가 예시: 별도의 매퍼 사용
// ItemMapper.java
@Mapper
public interface ItemMapper {
@Mapping(target = "description", ignore = true)
ItemDto toDto(Item item);
}
// OrderMapper.java
@Mapper(uses = ItemMapper.class)
public interface OrderMapper {
OrderDto toDto(Order order);
}
설명: ItemMapper
에서 description
필드를 무시하도록 설정하였고, OrderMapper
는 ItemMapper
를 사용하여 Order
의 items
리스트를 매핑합니다.
추가 예시: 매핑 메서드 지정
// OrderMapper.java
@Mapper
public interface OrderMapper {
@Mapping(target = "items", qualifiedByName = "mapItems")
OrderDto toDto(Order order);
@Named("mapItems")
default List<ItemDto> mapItems(List<Item> items) {
if (items == null) {
return null;
}
return items.stream()
.map(this::mapItem)
.collect(Collectors.toList());
}
@Mapping(target = "description", ignore = true)
ItemDto mapItem(Item item);
}
설명: mapItems
메서드를 통해 items
리스트를 매핑하고, 개별 Item
은 mapItem
메서드를 사용하여 매핑합니다. mapItem
에서 description
필드를 무시하도록 설정하였습니다.
주의사항
- 유지보수성 고려: 매핑이 복잡해질 경우 별도의 매퍼를 사용하는 것이 코드의 가독성과 유지보수에 좋습니다.
- 성능 고려:
@AfterMapping
을 통한 후처리는 추가 연산을 필요로 하므로 성능에 영향을 줄 수 있습니다. - 일관성 유지: 매핑 전략을 프로젝트 전반에 걸쳐 일관되게 적용하는 것이 중요합니다.
이렇게 MapStruct에서 컬렉션의 하위 객체 필드를 무시하는 방법과 그 대안에 대해 알아보았습니다. 실제 개발 상황에 맞게 적절한 방법을 선택하여 사용하시길 바랍니다. 도움이 되셨길 바라며, 항상 즐거운 개발 되세요!
'IT' 카테고리의 다른 글
GPT와 심심이의 차이점: 인공지능 챗봇 비교 (4) | 2024.09.23 |
---|---|
MapStruct 사용 시 꼭 알아야 할 30가지 질문과 답변 (1) | 2024.09.21 |
Slack DM을 관리자가 읽을 수 있나요? (2) | 2024.09.20 |
구체적인 사례로 알아보는 GPT-3.5와 GPT-4의 차이점 (2) | 2024.09.17 |
갤럭시 버즈 프로3 내돈내산 실제 핵심 리뷰 (1) | 2024.07.15 |