首页 > 解决方案 > 条件映射 ((condition) ? get-this : get-that) 与 Org.ModelMapper

问题描述

我试图根据地图的根/源的条件有条件地使用一个或另一个吸气剂。A有参考B;但是,它(引用)允许为 null。当引用不为空时,我想使用它的属性(B)。但是,当引用为 null时,我想使用源 ( A) 中的属性。

这有点业务逻辑,但我们的系统中有很多数据模型都遵循这种模式。使用映射器库是有益的,在我看来,逻辑很简单——它与使用库的Condition.

当我在 getter 中使用逻辑时,它会启动并初始化;但是,当地图实际用于映射对象时,我IllegalArgumentException从 Model-Mapper 得到一个说object is not an instance of declaring class.

我无法将图书馆正确地融入Condition解决方案。它似乎更像是一劳永逸,而不是 if-or-else。我有一个映射器,它首先在源 ( A) 上使用 getter。然后在下一行我调用条件Conditions.isNotNull())和 map a -> a.getB().getDescription()。所以在我看来,它的工作原理是首先description使用A. 然后它将“覆盖”该值,a.getB().getDescription()但前提a.getB()是它不为空。但是,它似乎不是那样工作的。相反,对于a.getB()返回 null 的实例,我将null其视为 DTO 的description.

总之,我希望能够执行以下操作:

modelMapper.createTypeMap(A.class, FlatAB.class).addMappings(mapper -> {
    mapper.map(a -> a.getB() != null ? a.getB().getDescription() : 
            a.getDescription(), FlatAB::setDescription);
});

这是一些示例代码来演示我面临的问题。

import java.util.Optional;
import org.junit.Assert;
import org.junit.Test;
import org.modelmapper.ModelMapper;

public class TestMappingConditionalGettersWithModelMapper {

  @Test
  public void testConditionalGetter() {
    ModelMapper modelMapper = new ModelMapper();

    modelMapper.createTypeMap(A.class, FlatAB.class).addMappings(mapper -> {

      // mapper.map(a -> a.getB() != null ? a.getB().getDescription() : a.getDescription(), FlatAB::setDescription);

      mapper.map(a -> Optional
          .ofNullable(a.getB())
          .map(B::getDescription)
          .orElseGet(a::getDescription), FlatAB::setDescription);
    });

    // first try A with no relationship
    A a = new A();
    a.setDescription("description of A");
    FlatAB flatAB1 = modelMapper.map(a, FlatAB.class);
    Assert.assertEquals("they should equal", a.getDescription(), flatAB1.getDescription());


    // now try it WITH a relationship
    A a2 = new A();
    a2.setDescription("description of A2");
    B b = new B();
    b.setDescription("description of B");
    a2.setB(b);
    FlatAB flatAB2 = modelMapper.map(a2, FlatAB.class);
    Assert.assertEquals("they should equal", b.getDescription(), flatAB2.getDescription());
  }

}

class A {

  private String description;
  private B b;

  /*
   .....
   .....
   many other properties
   .....
   ....
   */

  public B getB() {
    return b;
  }

  public void setB(B b) {
    this.b = b;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

}

class B {

  private String description;

  /*
   .....
   .....
   many other properties
   .....
   ....
   */

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }
}

标签: javamodelmapper

解决方案


我在图书馆的 Github 上提出了这个问题,并从维护者Chun-Han, Hsiao那里得到了很好的回答。

如果没有转换器,我们无法将多个源属性映射到目标。

请试试:

modelMapper.addMappings(mapper ->
    mapper.using(ctx -> ctx.getSource().getB() != null
        ? ctx.getSource().getB().getDescription()
        : ctx.getSource().getDescription())
      .map(src -> src, FlatAB::setDescription));

我发现这ctx.getSource()可能需要强制转换——但我确信有一种方法可以输入类型。


推荐阅读