MapStruct:合并父对象时调用子对象的合并

MapStruct: Call merge of Child object while merging Parent object

我有两种合并方法,一种用于父对象,一种用于子对象

@Mappings({
    @Mapping(target="childs", source="childs")
})
void merge(@MappingTarget Target result, Source request);

void merge(@MappingTarget ChildTarget result, ChildSource request);

现在MapStruct生成第一个合并方法的实现如下

@Override
    public void merge(Target result, Source request) {
        if ( request == null ) {
            return;
        }

        if ( result.getChilds() != null ) {
// I want to instruct MapStruct to call merge for Child object
            List<ChildTarget> list = childSourceListToChildTargetList( request.getChilds() );
            if ( list != null ) {
                result.getChilds().clear();
                result.getChilds().addAll( list );
            }
            else {
                result.setChilds( null );
            }
        }
        else {
            List<ChildTarget> list = childSourceListToChildTargetList( request.getChilds() );
            if ( list != null ) {
                result.setChilds( list );
            }
        }
    }

protected List<ChildTarget> childSourceListToChildTargetList(List<ChildSource> list) {
        if ( list == null ) {
            return null;
        }

        List<ChildTarget> list1 = new ArrayList<ChildTarget>( list.size() );
        for ( ChildSource childSource : list ) {
            list1.add( childSourceToChildTarget( childSource ) );
        }

        return list1;
    }

我尝试了各种注释,但无法找到任何确切的解决方案

如果我理解正确你正在尝试做什么,一种可能的解决方案是使用 expressions:

@Mappings({
    @Mapping(target="childs",
             expression = "java( mergeChilds(target, request) )")
})
void merge(@MappingTarget Target result, Source request);

请注意 mergeChilds 必须具有以下签名:

List<ChildTarget> mergeChilds(Target target, Source source)

例如,它可以是您界面中的一个 default 方法,并且必须包含您的域特定逻辑来处理合并。

MapStruct 无法正确执行此操作。查看 here 原因。如何合并集合与用例密切相关(正如您已经发现的那样)。

但是你总是可以自己做,MapStruct 会select那个方法。

    @Mapping(target="childs", source="childs") // you can omit @Mappings in java8
    void merge(@MappingTarget Target result, Source request);

    default void merge(@MappingTarget List<ChildTarget> result, List<ChildSource> source ) {
       // write whatever merge functionality you desire and call 'merge' for the ChildTarget / ChildSource here
    }  

    void merge(@MappingTarget ChildTarget result, ChildSource request);
}