使用ModelMapper级联属性映射

3
考虑6个POJO类:3个DAO和3个DTO。
DAOs: "A","B","C" DTOs: "One","Two","Three"
public class A {

    private int idOfA;
    private String name;
    private List<B> b;

    // getters, setters, etc...
}

public class B {

    private int idOfB;
    private String name;
    private List<C> c;

    // getters, setters, etc...
}

public class C {

    private int idOfC;
    private String name;

    // getters, setters, etc...
}



public class One {

    private int id;
    private String name;
    private List<Two> two;

    // getters, setters, etc...
}

public class Two {

    private int id;
    private String name;
    private List<Three> Three;

    // getters, setters, etc...
}

public class Three {

    private int id;
    private String name;

    // getters, setters, etc...
}

"A" 包含一个 "B" 列表,"B" 包含一个 "C" 列表。
"One" 包含一个 "Two" 列表,"Two" 包含一个 "Three" 列表。
"A" 通过 "A2One" 映射到 "One","B" 通过 "B2Two" 映射到 "Two","C" 通过 "C2Three" 映射到 "Three"。
public class A2One extends PropertyMap<A, One> {

    @Override
    protected void configure() {
        map().setId(source.getIdOfA());
        map().setName(source.getName());

        when(Conditions.isNotNull()).using(new BListConverter()).map(source.getBs()).setTwos(null);
    }
}

public class BListConverter extends AbstractConverter<List<B>, List<Two>> {

        @Override
        protected List<Two> convert(List<B> source) {

            List<Two> twos = new ArrayList<Two>(source.size());

            for(B b : source) {
                Two t = new Two();
                t.setId(b.getId());
                t.setName(b.getName());

                // Ignore list of Cs contained in B for now

                twos.add(t);
            }

            return twos;
        }
}

public class B2Two extends PropertyMap<B, Two> {

    @Override
    protected void configure() {
        map().setId(source.getIdOfB());
        map().setName(source.getName());

        when(Conditions.isNotNull()).using(new CListConverter()).map(source.getCs()).setThrees(null);
    }
}

B2Two和C2Three的代码与A2One非常相似。

所以我有一个问题:

目前,“A”中包含的列表与“One”之间的转换是通过自定义转换器完成的(它有效),但我正在重复B2Two应该执行的相同操作(将Bs映射到Twos)。

在列表需要映射时,是否有任何级联属性映射的方法(A2One->B2Two->C2Three),而不必编写仅重现属性映射正在执行的转换器?

备选方案1:使用泛型List,List创建自定义TypeMap,将其转发到正确的属性/类型映射。

备选方案2:在A2One中使用以下内容来处理列表

mapper.addMappings(new BList2TwoList());
when(Conditions.isNotNull()).withProvider(listProvider).map().setTwos(mapper.map(source.getBs(), List.class));

ListProvider扩展了AbstractProvider并返回一个新的ArrayList

备选方案3:???

有什么想法吗?网站上更复杂的映射问题的文档非常贫乏,我不一定要寻找替代框架。如果提供替代方案,则必须允许轻松重构(因此Dozer和Orika基本上被淘汰了)。

提前致谢

更新: 在撰写本文时,ModelMapper已经基本死亡,实际上不支持列表或映射的级联,因此您将被迫为每个也可能是列表的对象编写映射和转换器。
此外,我发现Orika通过扩展MapperBase具有易于重构的映射。此外,Orika可以透明地处理单个bean和bean列表的映射(使用单个映射规则处理两种情况)。

更新2: 在Orika中,可以使用CustomMapper进行双向深度嵌套集合映射。这使得双向映射实现成为可能,并允许它们级联到其他自定义映射器中。A2One将持有B2Two的实例,并在映射“A”中包含的“B”时透明地使用它。

感谢 Didier 提供适当的漂亮打印编辑。 - xelamitchell
2
ModelMapper现在仍然很活跃 - 版本0.4.0刚刚发布。我始终乐于改进库,如果您不介意发布它,我会很感兴趣看看您的Orika解决方案是什么样子的。 - Jonathan
谢谢您的回复,Jonathan。基本上我的情况是,虽然ModelMapper提供了一个非常友好的界面(不使用字符串映射属性),但它不能以透明的方式执行双向映射(因为PropertyMap的泛型实际上是源和目标,而不是相互映射的两个POJO)。我遇到的另一个问题是,对于封装在对象中的深度嵌套集合,使用PropertyMap变得有些棘手,因为我无法级联内部项的映射器(如上所述的问题)。 - xelamitchell
2个回答

2

我想我只是想表明,现在使用模型映射器可以实现这一点...

它支持列表(至少在版本0.7.5上)。

要执行此操作的PropertyMap应如下所示:

public class A2One extends PropertyMap<A, One> {

    @Override
    protected void configure() {
        map().setId(source.getIdOfA());
        map().setName(source.getName());

        map(source.getB()).setOne(null);
    }
}

1
使用Orika,我能够以简单友好的方式获得所有所需的要求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接