1. 概述

Project Lombok 是一个消除样板代码的利器,让我们能更专注于核心业务逻辑。

同样,MapStruct 也是一个在 Java Bean 之间做映射时减少样板代码的库。

本文将探讨如何高效地结合使用这两个工具。

2. 环境配置

pom.xml 中添加以下依赖:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.6.0.Beta2</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.32</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok-mapstruct-binding</artifactId>
    <version>0.2.0</version>
</dependency>

⚠️ 注意:lombok-mapstruct-binding 是关键依赖,确保两个注解处理器能正确协同工作。

3. MapStruct 与 Lombok 集成实践

我们将重点使用 Lombok 的 @Builder@Data 注解:

  • @Builder:通过建造者模式创建对象
  • @Data:自动生成 getter/setter 等基础方法

3.1. Java POJO 定义

先定义一个简单的源对象:

@Data
public class SimpleSource {
    private String name;
    private String description;
}

再定义两个目标对象,分别使用不同注解:

@Data
public class SimpleDestination {
    private String name;
    private String description;
}
@Builder
@Getter
public class LombokDestination {
    private String name;
    private String description;
}

3.2. 使用 @Mapper 注解

MapStruct 会根据 @Mapper 注解自动生成实现类。定义映射接口:

@Mapper
public interface LombokMapper {
    SimpleDestination sourceToDestination(SimpleSource source);
    LombokDestination sourceToLombokDestination(SimpleSource source);
}

执行 mvn clean install 后,在 /target/generated-sources/annotations/ 目录下生成实现类:

public class LombokMapperImpl implements LombokMapper {

    @Override
    public SimpleDestination sourceToDestination(SimpleSource source) {
        if ( source == null ) {
            return null;
        }

        SimpleDestination simpleDestination = new SimpleDestination();

        simpleDestination.setName( source.getName() );
        simpleDestination.setDescription( source.getDescription() );

        return simpleDestination;
    }

    @Override
    public LombokDestination sourceToLombokDestination(SimpleSource source) {
        if ( source == null ) {
            return null;
        }

        LombokDestination.LombokDestinationBuilder lombokDestination = LombokDestination.builder();

        lombokDestination.name( source.getName() );
        lombokDestination.description( source.getDescription() );

        return lombokDestination.build();
    }
}

关键差异点: ✅ SimpleDestination:通过构造函数创建 + setter 赋值
LombokDestination:通过 builder() 方法链式调用构建

3.3. 测试验证

@Test
void whenDestinationIsMapped_thenIsSuccessful() {
    SimpleSource simpleSource = new SimpleSource();
    simpleSource.setName("file");
    simpleSource.setDescription("A text file.");

    SimpleDestination simpleDestination = lombokMapper.sourceToDestination(simpleSource);
    Assertions.assertNotNull(simpleDestination);
    Assertions.assertEquals(simpleSource.getName(), simpleDestination.getName());
    Assertions.assertEquals(simpleSource.getDescription(), simpleDestination.getDescription());

    LombokDestination lombokDestination = lombokMapper.sourceToLombokDestination(simpleSource);
    Assertions.assertNotNull(lombokDestination);
    Assertions.assertEquals(simpleSource.getName(), lombokDestination.getName());
    Assertions.assertEquals(simpleSource.getDescription(), lombokDestination.getDescription());
}

测试结果验证了两种映射方式都能正确转换对象属性。

4. 总结

通过本文实践,我们实现了:

  1. 减少样板代码:Lombok 自动生成基础方法,MapStruct 自动生成映射逻辑
  2. 提升代码可读性:声明式映射替代手写转换逻辑
  3. 开发效率提升:两个工具协同工作,避免重复劳动

关键踩坑点:

  • 务必添加 lombok-mapstruct-binding 依赖
  • @Builder@Data 生成的代码结构不同,MapStruct 会自动适配

完整代码示例可在 GitHub 获取。


原始标题:Using MapStruct With Lombok | Baeldung