MapStruct的@Named和@Mapping的qualifiedByName属性如何使用?
摘要:一、 背景 在 Java 应用开发中对象之间的转换(如 DTO 与 Entity 的互转)是一项频繁且琐碎的任务。MapStruct 框架极大地解放了开发者的生产力。它通过在编译期生成类型安全、高性能的映射代码,避免了手动编写大量样板代码的
一、 背景
在 Java 应用开发中对象之间的转换(如 DTO 与 Entity 的互转)是一项频繁且琐碎的任务。MapStruct 框架极大地解放了开发者的生产力。它通过在编译期生成类型安全、高性能的映射代码,避免了手动编写大量样板代码的繁琐,也规避了其他反射式框架(如 Apache BeanUtils)在运行时可能带来的性能损耗和类型安全问题。
现实的业务逻辑远比简单的字段复制要复杂。
经常会遇到以下场景:
数据类型不一致:需要将 String 转换为 LocalDateTime 或 Double。
枚举与代码值转换:需要将程序内部的枚举(Enum)转换为数据库或外部接口使用的代码(String 或 Integer)。
字典值映射:需要根据一个名称(如"北蔡镇")查询字典表,获取其对应的ID(如"1")。
复杂的业务计算:需要根据多个源字段的值,经过计算后,赋值给目标对象的一个字段。
在这些情况下默认映射机制(即同名同类型字段自动映射)便显得力不从心。为了解决这一问题,MapStruct 提供了一套强大而灵活的自定义映射机制,其核心便是 @Named 注解与 @Mapping 注解中的 qualifiedByName 属性。这对"黄金搭档"赋予了开发者完全控制映射逻辑的能力,让复杂的转换变得优雅而高效。
二、 基础使用
在深入细节之前先通过一个简单的例子快速了解 @Named 和 qualifiedByName 如何协同工作。
假设有一个源对象 Source 和一个目标对象 Target,需要将 Source 的 status 字符串(如 "active")转换为 Target 的 statusCode 整数(如 1)。
第一步:定义 DTO 和 Mapper 接口
// 源对象
public class Source {
private String status;
// getters and setters
}
// 目标对象
public class Target {
private Integer statusCode;
// getters and setters
}
// Mapper 接口
@Mapper
public interface StatusMapper {
StatusMapper INSTANCE = Mappers.getMapper(StatusMapper.class);
@Mapping(source = "status", target = "statusCode", qualifiedByName = "statusToCode")
Target toTarget(Source source);
}
第二步:在 Mapper 接口中定义带 @Named 注解的转换方法
需要在 StatusMapper 接口中,提供一个将 String 转换为 Integer 的具体方法,并用 @Named 为其命名。
@Mapper
public interface StatusMapper {
StatusMapper INSTANCE = Mappers.getMapper(StatusMapper.class);
@Mapping(source = "status", target = "statusCode", qualifiedByName = "statusToCode")
Target toTarget(Source source);
/**
* 定义一个名为 "statusToCode" 的自定义转换方法
* @param status 状态字符串
* @return 状态码
*/
@Named("statusToCode")
default Integer statusToCode(String status) {
if ("active".equals(status)) {
return 1;
} else if ("inactive".equals(status)) {
return 0;
}
return null;
}
}
工作流程解析:
当 MapStruct 编译器处理 toTarget 方法时,它看到了 statusCode 字段的 @Mapping 注解。
