如何自定义ModelMapper

约翰·亨克尔:

我想用ModelMapper到实体转化为DTO和背部。主要是它的工作原理,但我怎么定制。它有这么多的选择,很难找出哪里开始。什么是最好的做法?

下面我将回答它自己,但如果另一个答案是更好,我会接受它。

约翰·亨克尔:

首先这里有一些链接

我毫米的印象是,它是很好的设计。该代码是坚实的,读来引人入胜。然而,该文档是非常简洁,除了极少数的例子。另外,API是混乱,因为似乎有10种方式做任何事情,也没有为什么你会做这样或那样的指示。

有两种选择:推土机是最流行的,并Orika得到的易用性很好的评价。

假设您仍想使用毫米,这是我已经了解了。

主类,ModelMapper应该是在你的应用程序是独生子。对我来说,这意味着一个使用Spring @Bean。它的工作原理简单的情况下,开箱即用。例如,假设你有两类:

class DogData
{
    private String name;
    private int mass;
}

class DogInfo
{
    private String name;
    private boolean large;
}

用适当的getter / setter方法。你可以这样做:

    ModelMapper mm = new ModelMapper();
    DogData dd = new DogData();
    dd.setName("fido");
    dd.setMass(70);
    DogInfo di = mm.map(dd, DogInfo.class);

与“名”将被复制从DD到迪。

有许多方法来定制毫米,但首先你需要了解它是如何工作的。

的毫米对象包含对于每个有序对类型,如<DogInfo,DogData>和<DogData,DogInfo>一个的TypeMap将为二TypeMaps。

每一个的TypeMap包含一个属性映射与映射列表。因此,在示例中的毫米将自动创建的TypeMap <DogData,DogInfo>包含具有单个映射属性映射。

我们可以这样写

    TypeMap<DogData, DogInfo> tm = mm.getTypeMap(DogData.class, DogInfo.class);
    List<Mapping> list = tm.getMappings();
    for (Mapping m : list)
    {
        System.out.println(m);
    }

并且它会输出

PropertyMapping[DogData.name -> DogInfo.name]

当你调用mm.map()这个是做什么的,

  1. 查看是否的TypeMap尚未存在,如果不产生用于<S,d>源/目标类型的TypeMap
  2. 调用类型映射条件,如果返回FALSE,什么也不做,STOP
  3. 调用的TypeMap 提供商如果需要构建一个新的目标对象
  4. 调用的TypeMap 预转换器(如果有)
  5. 请执行下列操作之一:
    • 如果类型映射有一个自定义的转换器,把它
    • 或者,生成一个属性映射(基于配置标志以及任何自定义映射添加的),并使用它(注:类型映射也有可选的自定义前/ PostPropertyConverters那我想会在之前和之后这点上运行的每个映射。)
  6. 调用的TypeMap PostConverter如果它有一个

警告:该流程图是那种记录,但我猜了很多,所以它可能不是正确的!

您可以自定义每一个步骤这个过程。但是,这两个最常见的是

  • 步骤5a。 - 写定制的TypeMap转换器,或
  • 步骤5b。 - 写自定义属性映射。

下面是一个样本定制的TypeMap转换器

    Converter<DogData, DogInfo> myConverter = new Converter<DogData, DogInfo>()
    {
        public DogInfo convert(MappingContext<DogData, DogInfo> context)
        {
            DogData s = context.getSource();
            DogInfo d = context.getDestination();
            d.setName(s.getName());
            d.setLarge(s.getMass() > 25);
            return d;
        }
    };

    mm.addConverter(myConverter);

注意转换器是单向的你如果你想定制DogInfo到DogData再写。

下面是一个样本自定义属性映射

    Converter<Integer, Boolean> convertMassToLarge = new Converter<Integer, Boolean>()
    {
        public Boolean convert(MappingContext<Integer, Boolean> context)
        {
            // If the dog weighs more than 25, then it must be large
            return context.getSource() > 25;
        }
    };

    PropertyMap<DogData, DogInfo> mymap = new PropertyMap<DogData, DogInfo>()
    {
        protected void configure()
        {
            // Note: this is not normal code. It is "EDSL" so don't get confused
            map(source.getName()).setName(null);
            using(convertMassToLarge).map(source.getMass()).setLarge(false);
        }
    };

    mm.addMappings(mymap);

该pm.configure功能是很大胆的。它不是实际的代码。这是虚拟EDSL代码是被莫名其妙地解释。例如,该参数二传手是不相关的,它只是一个占位符。你可以做很多的东西在这里,如

  • 当(条件).MAP器(getter).setter
  • 。当(条件).skip()setter方法 - 忽略场。
  • 使用(转换器).MAP(吸气).setter - 自定义字段转换器
  • 用(供应商).MAP(吸气).setter - 自定义字段构造函数

注意:自定义映射添加到默认的映射,这样你就不会需要,例如,指定

            map(source.getName()).setName(null);

在您的自定义PropertyMap.configure()。

在这个例子中,我不得不写一个转换器,以整数映射到布尔。在大多数情况下,因为MM会自动转换成整数转字符串,等等。这不会是必要的

有人告诉我,你还可以创建映射使用Java 8拉姆达表达式。我试过,但我无法弄清楚。

最后的建议和最佳实践

默认情况下毫米的用途MatchingStrategies.STANDARD是危险的。它可以很容易地选择了错误的映射,并导致奇怪,很难找到错误。而如果明年有人将新列添加到数据库?所以,不要做。请确保您使用严格模式:

    mm.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

总是写单元测试,确保所有的映射验证。

    DogInfo di = mm.map(dd, DogInfo.class);
    mm.validate();   // make sure nothing in the destination is accidentally skipped

固定与任何验证失败mm.addMappings(),如上所示。

把你所有的映射在一个集中的地方,在那里创建毫米单。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章