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 注解。
阅读全文