使用MapStruct和Lombok转换数据对象

Project Lombok是一个有助于样板代码的库,使我们能够更加专注于核心应用程序逻辑。

类似地,当我们需要两个 Java bean 之间的映射时,MapStruct是另一个可以帮助提供样板的库。

在本教程中,我们将研究如何有效地结合使用这两个库:
使用@Builder和@Data Lombok 注释。前者允许通过Builder 模式创建对象,而后者通过 setter 提供基于构造函数的对象创建。

设置
我们将mapstruct、lombok和lombok-mapstruct-binding依赖项添加到我们的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>

MapStruct 与 Lombok 集成
我们将在设置中使用@Builder和@Data Lombok 注释。前者允许通过Builder 模式创建对象,而后者通过 setter 提供基于构造函数的对象创建。

1. Java POJO 设置
现在,让我们首先为映射器定义一个简单的源类:

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

接下来,我们为映射器定义一个简单的目标类:

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

最后,我们还将定义另一个目标类,但使用@Builder Lombok 注释:

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

2. 使用@Mapper注解
当我们使用@Mapper注释时,MapStruct会自动创建映射器实现。

让我们定义映射器接口:

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

当我们执行mvn clean install命令时,会在/target/generated-sources/annotations/文件夹下创建mapper实现类。

我们来看一下生成的实现类:

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();
    }
}

正如我们在这里看到的,实现有两种方法可以将源对象映射到不同的目标。然而,主要的区别在于目标对象的构建方式。

该实现使用LombokDestination类的builder()方法。另一方面,它使用构造函数创建SimpleDestination对象并使用 setter 映射变量。

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());
}

正如我们可以在上面的测试用例中验证的那样,映射器实现成功地将源 POJO 映射到两个目标 POJO。

结论
在本文中,我们研究了如何结合使用 MapStruct 和 Lombok 来帮助我们减少样板代码的编写,从而增强代码的可读性并提高开发过程的效率。