
在进行对象映射时,我们经常会遇到需要将一个额外参数(例如,一个全局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主要用于定义源对象和目标对象之间的属性映射关系,而非参数的传递机制。
MapStruct从1.2版本开始引入了@Context注解,专门用于解决此类上下文参数的传递问题。当一个参数被@Context注解标记时,MapStruct会识别它为“上下文参数”,并尝试将其传递给所有可能被调用的、接受相同类型和名称的@Context参数的子映射方法。
首先,在列表映射方法中,将需要传播的额外参数标记为@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。
为了解决上述问题,我们需要在Mapper接口中添加一个default方法,作为MapStruct在处理列表时调用的“代理”。这个代理方法的作用是显式地将带有@Context注解的参数传递给原始的单对象映射方法。
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
}
}通过遵循上述指导,你可以在MapStruct中有效地管理和传播额外的上下文参数,从而实现更灵活和强大的映射逻辑。
以上就是MapStruct:在列表映射中传递并传播额外参数的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号