You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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方法支持向已存在的目标对象填充属性的特性:

  1. 当转换SourceA到Dest时,首先会把www映射到ddd;
  2. 然后拿到sourceB属性,调用已定义好的SourceB→Dest映射,将sourceB的xxx/yyy/zzz分别填充到同一个Dest对象的aaa/bbb/ccc字段中;
  3. 最终得到的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 17:07:43