본문 바로가기

IT

MapStruct에서 List 하위 객체 ignore 하는 방법

728x90
반응형
728x170

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
}

위의 클래스에서 Itemdescription 필드를 ItemDto로 매핑할 때 무시하고 싶다고 가정해봅시다.

 

해결 방법

 

1. 하위 객체에 대한 별도의 매퍼 생성

ItemItemDto 간의 매핑을 담당하는 별도의 매퍼 인터페이스를 생성하고, 그 안에서 무시하고자 하는 필드를 지정합니다.

@Mapper
public interface ItemMapper {
    @Mapping(target = "description", ignore = true)
    ItemDto toDto(Item item);
}

그 다음, OrderOrderDto를 매핑하는 매퍼에서 uses 속성을 통해 ItemMapper를 사용하도록 지정합니다.

@Mapper(uses = ItemMapper.class)
public interface OrderMapper {
    OrderDto toDto(Order order);
}

이렇게 하면 OrderMapperItemMapper를 사용하여 Item 리스트를 ItemDto 리스트로 매핑하며, 그 과정에서 description 필드는 무시됩니다.

 

 

2. @NamedqualifiedByName 사용

별도의 매퍼를 생성하지 않고, 매퍼 내부에서 특정 메서드를 지정하여 매핑할 수도 있습니다.

@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로 직접 무시할 수 없습니다.
  • 별도의 매퍼 사용: 하위 객체 타입에 대한 매퍼를 별도로 정의하여 원하는 필드를 무시합니다.
  • 매핑 메서드 지정: @NamedqualifiedByName을 사용하여 특정 매핑 메서드를 지정합니다.
  • 후처리 로직 추가: @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 필드를 무시하도록 설정하였고, OrderMapperItemMapper를 사용하여 Orderitems 리스트를 매핑합니다.

 

추가 예시: 매핑 메서드 지정

// 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 리스트를 매핑하고, 개별 ItemmapItem 메서드를 사용하여 매핑합니다. mapItem에서 description 필드를 무시하도록 설정하였습니다.

 

주의사항

  • 유지보수성 고려: 매핑이 복잡해질 경우 별도의 매퍼를 사용하는 것이 코드의 가독성과 유지보수에 좋습니다.
  • 성능 고려: @AfterMapping을 통한 후처리는 추가 연산을 필요로 하므로 성능에 영향을 줄 수 있습니다.
  • 일관성 유지: 매핑 전략을 프로젝트 전반에 걸쳐 일관되게 적용하는 것이 중요합니다.

 

이렇게 MapStruct에서 컬렉션의 하위 객체 필드를 무시하는 방법과 그 대안에 대해 알아보았습니다. 실제 개발 상황에 맞게 적절한 방법을 선택하여 사용하시길 바랍니다. 도움이 되셨길 바라며, 항상 즐거운 개발 되세요!

728x90
반응형
그리드형