如何用ModelMapper复用映射规则实现对象扁平化转换?
复用ModelMapper中已定义的TypeMap实现嵌套对象映射
我明白你的需求:你已经定义了SourceB到Dest的映射规则,现在想在SourceA到Dest的映射里直接复用这个规则,避免重复配置嵌套对象的映射逻辑,同时保持一步完成SourceA到Dest的转换。
核心解决方案
你可以通过在SourceA到Dest的TypeMap中,为sourceB属性指定一个自定义的映射逻辑——直接调用已有的SourceB→Dest映射,将sourceB的属性合并到目标Dest对象中。具体写法如下:
ModelMapper mapper = new ModelMapper(); // 先定义SourceB到Dest的映射规则 mapper.createTypeMap(SourceB.class, Dest.class) .addMapping(SourceB::getXxx, Dest::setAaa) .addMapping(SourceB::getYyy, Dest::setBbb) .addMapping(SourceB::getZzz, Dest::setCcc); // 定义SourceA到Dest的映射,复用上面的SourceB映射 mapper.createTypeMap(SourceA.class, Dest.class) .addMapping(SourceA::getWww, Dest::setDdd) .addMappings(typeMap -> { // 处理sourceB属性:用已有的映射将sourceB的属性填充到当前Dest对象 typeMap.map(SourceA::getSourceB, (dest, sourceB) -> { mapper.map(sourceB, dest); }); });
原理说明
这里的关键是利用ModelMapper的map方法支持向已存在的目标对象填充属性的特性:
- 当转换
SourceA到Dest时,首先会把www映射到ddd; - 然后拿到
sourceB属性,调用已定义好的SourceB→Dest映射,将sourceB的xxx/yyy/zzz分别填充到同一个Dest对象的aaa/bbb/ccc字段中; - 最终得到的
Dest对象会同时包含来自SourceA和SourceB的所有映射属性,效果和你第一种直接配置的方式完全一致。
完整可运行示例
// 源对象类 class SourceA { private int www; private SourceB sourceB; // 构造器、getter、setter public SourceA(int www, SourceB sourceB) { this.www = www; this.sourceB = sourceB; } public int getWww() { return www; } public SourceB getSourceB() { return sourceB; } } class SourceB { private int xxx; private int yyy; private int zzz; public SourceB(int xxx, int yyy, int zzz) { this.xxx = xxx; this.yyy = yyy; this.zzz = zzz; } public int getXxx() { return xxx; } public int getYyy() { return yyy; } public int getZzz() { return zzz; } } // 目标对象类 class Dest { private int aaa; private int bbb; private int ccc; private int ddd; // setter和toString public void setAaa(int aaa) { this.aaa = aaa; } public void setBbb(int bbb) { this.bbb = bbb; } public void setCcc(int ccc) { this.ccc = ccc; } public void setDdd(int ddd) { this.ddd = ddd; } @Override public String toString() { return "Dest{aaa=" + aaa + ", bbb=" + bbb + ", ccc=" + ccc + ", ddd=" + ddd + "}"; } } // 测试代码 public class ModelMapperDemo { public static void main(String[] args) { ModelMapper mapper = new ModelMapper(); // 配置SourceB到Dest的映射 mapper.createTypeMap(SourceB.class, Dest.class) .addMapping(SourceB::getXxx, Dest::setAaa) .addMapping(SourceB::getYyy, Dest::setBbb) .addMapping(SourceB::getZzz, Dest::setCcc); // 配置SourceA到Dest的映射,复用SourceB的映射 mapper.createTypeMap(SourceA.class, Dest.class) .addMapping(SourceA::getWww, Dest::setDdd) .addMappings(typeMap -> { typeMap.map(SourceA::getSourceB, (dest, sourceB) -> mapper.map(sourceB, dest)); }); // 测试转换 SourceB sourceB = new SourceB(1, 2, 3); SourceA sourceA = new SourceA(4, sourceB); Dest dest = mapper.map(sourceA, Dest.class); System.out.println(dest); // 输出:Dest{aaa=1, bbb=2, ccc=3, ddd=4} } }
这种方式的优势在于:当你需要修改SourceB到Dest的映射规则时,只需要修改对应的TypeMap配置,不需要在SourceA的映射中重复调整,极大提升了复杂场景下的代码可维护性。
内容的提问来源于stack exchange,提问作者Vinicius
相关产品推荐
相关产品推荐

