首页 > Java > java教程 > 正文

MapStruct:在列表映射中传递并传播额外参数的教程

碧海醫心
发布: 2025-10-01 14:05:24
原创
835人浏览过

MapStruct:在列表映射中传递并传播额外参数的教程

本教程详细介绍了如何在MapStruct中,将一个额外的参数(如ID)从列表映射方法(如mapDTOs)向下传递并传播到其内部的单个对象映射方法(如map)。核心解决方案是利用@Context注解标记额外参数,并结合一个默认的代理方法来确保MapStruct能正确地将上下文参数传递给每个元素映射。

理解MapStruct中的参数传播需求

在进行对象映射时,我们经常会遇到需要将一个额外参数(例如,一个全局id、用户信息或某种配置)从一个顶层映射方法传递到其内部调用的子映射方法的情况。尤其是在处理集合(如list)的映射时,我们希望这个额外参数能够被集合中的每个元素的独立映射过程所感知和使用。

例如,假设我们有一个MyOM对象列表需要映射为MyEntity对象列表。同时,我们希望在每个MyEntity对象中都设置一个外部传入的id。如果只有一个单对象映射方法:

@Mapping(target = "id", expression = "java(id)")
MyEntity map(MyOM om, String id);
登录后复制

这个方法能够将传入的id设置到MyEntity的id字段。但当我们尝试为列表创建映射方法时,如何确保这个id参数也能被列表中的每个MyOM元素映射到其对应的MyEntity中呢?

List<MyEntity> mapDTOs(List<MyOM> dtos, String id); // 如何让这个id传递下去?
登录后复制

直接在mapDTOs方法上使用@Mapping注解通常不足以解决这个问题,因为@Mapping主要用于定义源对象和目标对象之间的属性映射关系,而非参数的传递机制。

使用@Context注解进行参数传播

MapStruct从1.2版本开始引入了@Context注解,专门用于解决此类上下文参数的传递问题。当一个参数被@Context注解标记时,MapStruct会识别它为“上下文参数”,并尝试将其传递给所有可能被调用的、接受相同类型和名称的@Context参数的子映射方法。

1. 声明列表映射方法

首先,在列表映射方法中,将需要传播的额外参数标记为@Context。请注意,这个方法本身不需要@Mapping注解,因为其主要功能是委托给单个元素的映射。

import org.mapstruct.Context;
import java.util.List;

// 假设MyOM和MyEntity已经定义
// public class MyOM { /* ... */ }
// public class MyEntity { String id; /* ... */ }

@Mapper // 确保你的接口是MapStruct的Mapper
public interface MyMapper {

    // 单个对象映射方法,用于设置id
    @Mapping(target = "id", expression = "java(id)")
    MyEntity map(MyOM om, String id);

    // 列表映射方法,使用@Context传播id
    List<MyEntity> mapDTOs(List<MyOM> dtos, @Context String id);
}
登录后复制

此时,如果直接运行,MapStruct可能会抱怨找不到一个接受@Context String id参数的单对象映射方法,或者生成一个不带id映射的新方法。这是因为MapStruct默认会寻找一个与列表元素类型匹配的单对象映射方法,而我们现有的map(MyOM om, String id)方法中的id并未被标记为@Context。

2. 添加代理(Default)方法

为了解决上述问题,我们需要在Mapper接口中添加一个default方法,作为MapStruct在处理列表时调用的“代理”。这个代理方法的作用是显式地将带有@Context注解的参数传递给原始的单对象映射方法。

来画数字人直播
来画数字人直播

来画数字人自动化直播,无需请真人主播,即可实现24小时直播,无缝衔接各大直播平台。

来画数字人直播 0
查看详情 来画数字人直播
import org.mapstruct.Context;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import java.util.List;

@Mapper
public interface MyMapper {

    // 原始的单个对象映射方法
    @Mapping(target = "id", expression = "java(id)")
    MyEntity map(MyOM om, String id);

    // 列表映射方法,使用@Context传播id
    List<MyEntity> mapDTOs(List<MyOM> dtos, @Context String id);

    // 代理方法:将带有@Context的id参数传递给原始的map方法
    default MyEntity mapContext(MyOM om, @Context String id) {
        return map(om, id);
    }
}
登录后复制

通过添加mapContext这个default方法,我们告诉MapStruct:当它需要映射单个MyOM并有一个@Context String id可用时,它应该调用mapContext。而mapContext内部又会调用我们预期的map(om, id)方法,从而实现了id参数的正确传播。

示例代码

假设我们有以下数据模型:

// 源对象
public class MyOM {
    private String name;
    // ... 其他字段
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

// 目标对象
public class MyEntity {
    private String id;
    private String entityName;
    // ... 其他字段
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getEntityName() { return entityName; }
    public void setEntityName(String entityName) { this.entityName = entityName; }
}
登录后复制

完整的Mapper接口:

import org.mapstruct.Context;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

import java.util.List;

@Mapper
public interface MyMapper {

    MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);

    // 单个对象映射方法,将om的name映射到entityName,并设置传入的id
    @Mapping(target = "entityName", source = "om.name")
    @Mapping(target = "id", expression = "java(id)")
    MyEntity map(MyOM om, String id);

    // 列表映射方法,使用@Context传播id
    List<MyEntity> mapDTOs(List<MyOM> dtos, @Context String id);

    // 代理方法:将带有@Context的id参数传递给原始的map方法
    default MyEntity mapContext(MyOM om, @Context String id) {
        return map(om, id);
    }
}
登录后复制

使用示例:

import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        MyOM om1 = new MyOM();
        om1.setName("Object A");

        MyOM om2 = new MyOM();
        om2.setName("Object B");

        List<MyOM> omList = Arrays.asList(om1, om2);
        String globalId = "GLOBAL_UUID_123";

        List<MyEntity> entityList = MyMapper.INSTANCE.mapDTOs(omList, globalId);

        for (MyEntity entity : entityList) {
            System.out.println("Entity ID: " + entity.getId() + ", Entity Name: " + entity.getEntityName());
        }
        // 预期输出:
        // Entity ID: GLOBAL_UUID_123, Entity Name: Object A
        // Entity ID: GLOBAL_UUID_123, Entity Name: Object B
    }
}
登录后复制

注意事项与总结

  1. MapStruct版本要求:@Context注解是在MapStruct 1.2版本中引入的。请确保你的项目使用的MapStruct版本不低于此。
  2. @Context参数的特性:@Context参数本身不被视为映射的源属性。它们的主要目的是在映射方法链中传递上下文信息。
  3. 代理方法的必要性:当你的单对象映射方法(如map(MyOM om, String id))中的额外参数并未标记为@Context,而列表映射方法(如mapDTOs(List<MyOM> dtos, @Context String id))中的额外参数标记为@Context时,代理方法是必需的。它充当了MapStruct在上下文参数和非上下文参数之间进行桥接的机制。
  4. 清晰的职责:通过这种方式,我们可以清晰地分离列表映射和单个元素映射的职责,同时确保上下文信息在整个映射过程中正确传递。
  5. 替代方案:对于更复杂的上下文管理,可以考虑将上下文参数封装在一个单独的上下文对象中,并在该对象上使用@Context,这样可以传递多个相关参数。

通过遵循上述指导,你可以在MapStruct中有效地管理和传播额外的上下文参数,从而实现更灵活和强大的映射逻辑。

以上就是MapStruct:在列表映射中传递并传播额外参数的教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号