MapStruct:映射前过滤列表

时间:2019-03-29 19:14:09

标签: mapstruct

我已经看到这个问题在其他地方问过,但不是在相同的背景下提出的,并且没有适合我们用例的答案。

假设我在源对象中有一个列表字段:

List<MySourceElement> mySourceList;

和相应的目标字段:

List<MyTargetElement> myTargetList;

我只是希望能够在执行mySourceList的标准映射器映射到myTargetList之前,通过MySourceElement的某些属性过滤源mySourceList中的元素。

假设MySourceElement具有一个布尔属性isValid,而我们的过滤谓词只是(isValid == true),并且MyTargetElement没有对应的布尔值。

我尝试了多种方法,包括@DecoratedWith和qualifiedBy:

    对于这种简单的用例,
  1. @DecoratedWith对于Guice注入来说变得太复杂/令人费解,并且在MapStruct文档中也将该功能列为jsr330的实验版本。

  2. qualifiedBy无法正常工作(即,我无法让mapstruct在实现中应用qualifiedBy方法)。

qualifiedBy方法类似于:

@FilterForValid    
public List<MySourceElement> filterForValid(List<MySourceElement> mySourceElement) {
    ... implementation ...
}

我的映射器声明就像:

@Mapping(source = "mySourceList", target = "myTargetList", qualifiedBy = FilterForValid.class)
Target sourceToTarget(Source source);

我想要一个qualifiedBy的实现,例如:

target.withMyTargetList( 
    mySourceListToMyTargetList(filterUtil.filterForValid(source.getMySourceList)));    

我很乐于弄清楚如何使用@BeforeMapping代替工作,但是我不清楚我将如何从文档中做到这一点,特别是因为出于所有意图和目的,源对象应该被认为是不可变的。

任何有关最简单,首选方法进行集合过滤以及以这种方式调用映射器的指南。

1 个答案:

答案 0 :(得分:1)

有一个请求的功能mapstruct/mapstruct#1610,该功能可以在此处使用开箱即用的支持。话虽如此,一种解决此问题的方法是使用@Context批注。然后,您的映射器将如下所示:

@Mapper
public interface MyMapper {


    Target map(Source source, @Context Predicate<MySourceElement> predicate);

    default List<MySourceElement> mapAndFilter(List<MySourceElement> list, @Context Predicate<MySourceElement> predicate) {
        List<MySourceElement> newList = new ArrayList<>();
        for(MySourceElement el : list) {
            if (predicate.test(el)) {
                newList.add(map(el));
            }
        }

        return newList;
    }

    MySourceElement map(MySourceElement el);
}