mapstruct-plus

Installation
SKILL.md

MapStruct Plus 使用指南

MapStruct Plus 是 MapStruct 的增强工具,基于 JSR 269 注解处理器,通过注解自动生成 Mapper 接口。 核心优势:只需在类上加一个 @AutoMapper 注解,即可自动生成双向转换代码,无需手写 Mapper 接口。

触发条件:当用户在 Java/Spring Boot 项目中需要以下操作时,请主动激活此 skill:

  • 在两个 Java 类之间进行对象转换(如 DTO <-> Entity, VO <-> DTO)
  • 使用 @AutoMapper、@AutoMapping、@AutoMappers 等注解
  • 配置 mapstruct-plus 依赖和注解处理器
  • 使用 Converter 进行对象转换操作
  • 处理枚举转换、Map 转对象、循环引用等场景
  • 解决 mapstruct-plus 相关的编译或运行时问题
  • 提到 BeanUtils.copyProperties、ModelMapper、对象拷贝、类型转换、DTO 转换等关键词

重要:MapStruct Plus 已内嵌 MapStruct,不要再引入 MapStruct 依赖,避免版本冲突。

快速上手

1. 添加依赖

SpringBoot 环境(推荐):

<properties>
    <mapstruct-plus.version>最新版本</mapstruct-plus.version>
</properties>
<dependencies>
    <dependency>
        <groupId>io.github.linpeilie</groupId>
        <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
        <version>${mapstruct-plus.version}</version>
    </dependency>
</dependencies>

注解处理器配置(maven-compiler-plugin 中必须添加):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>io.github.linpeilie</groupId>
                <artifactId>mapstruct-plus-processor</artifactId>
                <version>${mapstruct-plus.version}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

与 Lombok 配合(lombok >= 1.18.16), 需额外添加 lombok-mapstruct-binding:

<annotationProcessorPaths>
    <path>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
    </path>
    <path>
        <groupId>io.github.linpeilie</groupId>
        <artifactId>mapstruct-plus-processor</artifactId>
        <version>${mapstruct-plus.version}</version>
    </path>
    <path>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok-mapstruct-binding</artifactId>
        <version>0.2.0</version>
    </path>
</annotationProcessorPaths>

非 SpringBoot 环境: 依赖改为 mapstruct-plus(不是 starter),添加 @ComponentModelConfig(componentModel = "default") 配置类,使用 new Converter() 创建实例。

2. 声明映射关系

在任意一个类上加 @AutoMapper:

@AutoMapper(target = UserDto.class)
@Data
public class User {
    private String username;
    private int age;
}

3. 执行转换

// SpringBoot - 自动注入
@Autowired
private Converter converter;

UserDto dto = converter.convert(user, UserDto.class);
List<UserDto> dtoList = converter.convert(userList, UserDto.class);
User updated = converter.convert(dto, existingUser);  // 更新已有对象

核心注解速查

注解 位置 用途 核心属性
@AutoMapper 声明转换关系 target(必填), uses, reverseConvertGenerate, cycleAvoiding
@AutoMappers 多目标转换 包含多个 @AutoMapper
@AutoMapping 字段 自定义属性映射 target, source, dateFormat, numberFormat, ignore, expression, qualifiedByName
@AutoMappings 字段 多映射规则 包含多个 @AutoMapping, 用 targetClass 区分
@AutoEnumMapper 枚举类 枚举自动转换 value(枚举唯一标识字段名)
@AutoMapMapper Map转对象 无属性
@ReverseAutoMapping 字段 反向映射配置 source(目标类属性), target(源类属性)
@MapperConfig 类(全局) 模块配置 mapperPackage, unmappedTargetPolicy, nullValueMappingStrategy
@ComponentModelConfig 组件模型 componentModel(非SpringBoot设"default")
@Immutable 不可变标记 标记后update方法不修改target

注解的完整属性定义请查阅 references/annotations.md

常见场景示例

自定义属性映射

@AutoMapper(target = CarDto.class)
@Data
public class Car {
    @AutoMapping(target = "seat")              // 不同属性名
    private SeatConfiguration seatConfiguration;

    @AutoMapping(dateFormat = "yyyy-MM-dd HH:mm:ss")  // 日期格式
    private LocalDateTime orderTime;

    @AutoMapping(numberFormat = "$0.00")        // 数字格式
    private BigDecimal price;

    @AutoMapping(ignore = true)                // 忽略映射
    private String internal;

    @AutoMapping(defaultValue = "0")           // null时默认值
    private Integer count;

    @AutoMapping(expression = "java(String.join(\",\", source.getList()))")  // 表达式
    private List<String> list;
}

一对多转换

@AutoMappers({
    @AutoMapper(target = UserDto.class),
    @AutoMapper(target = UserVO.class)
})
@Data
public class User {
    @AutoMapping(targetClass = UserDto.class, target = "educations")
    private List<String> educationList;

    @AutoMappings({
        @AutoMapping(targetClass = UserDto.class, dateFormat = "yyyy-MM-dd"),
        @AutoMapping(targetClass = UserVO.class, ignore = true)
    })
    private Date birthday;
}

枚举自动转换

@AutoEnumMapper("code")
@Getter @AllArgsConstructor
public enum StatusEnum {
    ENABLED(1), DISABLED(0);
    private final Integer code;
}

// 实体中直接用枚举类型,会自动与 code 值互相转换
@AutoMapper(target = GoodsVo.class)
@Data
public class Goods {
    private StatusEnum status;  // 自动转为 Integer
}

Map 转对象

@AutoMapMapper
@Data
public class ConfigModel {
    private String name;
    private Integer value;
}
// converter.convert(map, ConfigModel.class)

需要引入 hutool-core 依赖(1.4.0+版本)。

循环引用(树形结构等)

@AutoMapper(target = TreeNodeDto.class, cycleAvoiding = true)
@Data
public class TreeNode {
    private TreeNode parent;
    private List<TreeNode> children;
}

自定义转换器

@Component
@Named("TitleTranslator")
public class Titles {
    @Named("EnglishToFrench")
    public String toFrench(String title) { ... }
}

@AutoMapper(target = FrenchRelease.class, uses = Titles.class)
@Data
public class EnglishRelease {
    @AutoMapping(qualifiedByName = "EnglishToFrench")
    private String title;
}

反向映射配置

@AutoMapper(target = Target.class)
@Data
public class Source {
    @AutoMapping(target = "targetName")
    @ReverseAutoMapping(source = "targetName", target = "sourceName")
    private String sourceName;
}

嵌套对象自动转换

当属性是自定义类型时,只要该类型也配置了 @AutoMapper,会自动递归转换:

@AutoMapper(target = CarDto.class)
public class Car {
    private Seat seat;  // 自动使用 Seat 的转换器
}

@AutoMapper(target = SeatDto.class)
public class Seat { ... }

Converter API

io.github.linpeilie.Converter 统一转换入口:

方法 说明
convert(source, TargetClass.class) 创建新目标对象
convert(source, existingTarget) 更新已有对象
convert(list, TargetClass.class) 列表批量转换
convert(source, Class, Consumer) 转换 + 后处理
convert(source, Class, CycleAvoidingMappingContext) 循环引用安全转换
convert(Map, Class) Map 转对象(需 @AutoMapMapper)

常见问题

问题 解决方案
"cannot find converter" 检查依赖/注解处理器, mvn clean compile, 检查 Spring 扫描包
"Couldn't retrieve @Mapper" MapStruct 依赖冲突, 排除其他依赖中的 MapStruct
NoSuchMethodError: Adapter 多模块冲突, 配置不同 adapterPackage
spring-boot-devtools 异常 去掉该依赖, 会修改 ClassLoader
生成代码位置 target/generated-sources 目录

完整排查指南请查阅 references/troubleshooting.md 注解完整属性请查阅 references/annotations.md 配置项详情请查阅 references/configuration.md

Installs
1
First Seen
Apr 1, 2026