java - 条件映射 ((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;
}
}
解决方案
我在图书馆的 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()
可能需要强制转换——但我确信有一种方法可以输入类型。
推荐阅读
- swift - 如何使 ObservableObject 符合 Codable 协议?
- javascript - 防止两个事件在彼此之后立即触发
- laravel - 从 Vagrant 访问 Lumen 公用文件夹
- excel - 在满足条件的情况下将单元格复制到另一张工作表循环
- java - 我可以使用动态编程降低时间复杂度吗?
- python-3.x - 如何在不指向文件路径的情况下打开文件?
- javascript - 检索通过ajax调用传递给php控制器的文件列表
- windbg - 调试“已添加具有相同键的项目”异常
- c++ - Cppcheck 静态代码分析器实际上可以检测到不太常见的警告,例如“相对路径遍历 (CWE-23)”或“缓冲区读取不足 (CWE-127)”吗?
- python-3.x - 给定一个方阵,计算其对角线之和之间的绝对差