
本文介绍了如何使用 Mapstruct 优雅地处理 Java 中包含递归结构的对象的序列化。通过定义多个 Mapper 接口,并结合 @Mapping 注解,可以实现将具有嵌套 List 结构的实体类转换为对应的响应类,避免手动编写复杂的转换逻辑,提高开发效率和代码可维护性。本文提供了一个完整的示例,展示了如何配置和使用 Mapstruct 来处理树形结构的序列化。
在 Java Web 应用开发中,经常需要将内部数据模型转换为对外暴露的 API 响应模型。当数据模型包含递归结构,例如树形结构时,手动编写序列化逻辑会变得非常繁琐且容易出错。Mapstruct 是一个强大的 Java Bean 映射器,可以自动生成类型安全的映射代码,极大地简化了对象转换的过程。本文将介绍如何利用 Mapstruct 处理包含递归结构的对象的序列化。
示例:树形结构的序列化
假设我们有一个 Tree 类,它包含一个 Leaf 列表,而每个 Leaf 又可以包含一个 Leaf 列表,形成一个树形结构。
@Builder
@Getter
@AllArgsConstructor
@FieldDefaults(level = PUBLIC)
public class Tree {
String name;
List leafs;
} @Builder
@Getter
@AllArgsConstructor
@FieldDefaults(level = PUBLIC)
public class Leaf {
String name;
List children;
} 我们需要将 Tree 转换为 TreeResponse,Leaf 转换为 LeafResponse。
立即学习“Java免费学习笔记(深入)”;
@Getter
@Setter
@FieldDefaults(level = PUBLIC)
public class TreeResponse {
String name;
List leafs;
} @Getter
@Setter
@FieldDefaults(level = PUBLIC)
public class LeafResponse {
String name;
List children;
} Mapstruct 的配置
为了实现上述转换,我们需要定义两个 Mapper 接口:TreeMapper 和 LeafMapperSecond。
基于Intranet/Internet 的Web下的办公自动化系统,采用了当今最先进的PHP技术,是综合大量用户的需求,经过充分的用户论证的基础上开发出来的,独特的即时信息、短信、电子邮件系统、完善的工作流、数据库安全备份等功能使得信息在企业内部传递效率极大提高,信息传递过程中耗费降到最低。办公人员得以从繁杂的日常办公事务处理中解放出来,参与更多的富于思考性和创造性的工作。系统力求突出体系结构简明
@Mapper
public interface TreeMapper {
@Mapping(target = "name", source = "entity.name")
TreeResponse map(Tree entity);
}@Mapper
public interface LeafMapperSecond {
LeafResponse map(Leaf entity);
List map(List entity);
} TreeMapper 负责将 Tree 转换为 TreeResponse,并使用 @Mapping 注解指定 name 属性的映射关系。LeafMapperSecond 负责将 Leaf 转换为 LeafResponse,并提供了一个用于转换 List
关键点在于定义两个 Mapper, LeafMapperSecond 需要包含转换单个 Leaf 和 List
测试用例
以下是一个测试用例,用于验证 Mapstruct 的配置是否正确。
private TreeMapper treeMapper = Mappers.getMapper(TreeMapper.class);
@Test
public void test() {
List leafs = new ArrayList<>();
leafs.add(Leaf.builder().name("Leaf 1").build());
leafs.add(
Leaf.builder()
.name("Leaf 2")
.children(
Arrays.asList(
Leaf.builder()
.name("Leaf Children 1")
.children(
Arrays.asList(
Leaf.builder()
.name("Leaf Children 1.1")
.build(),
Leaf.builder()
.name("Leaf Children 1.2")
.build()))
.build(),
Leaf.builder().name("Leaf Children 2").build()))
.build());
Tree tree = Tree.builder().name("tree name").leafs(leafs).build();
TreeResponse treeResponse = treeMapper.map(tree);
assertEquals(treeResponse.name, "tree name");
assertEquals(treeResponse.leafs.size(), 2);
LeafResponse leafWithChildren =
treeResponse.leafs.stream()
.filter(l -> l.name.equals("Leaf 2"))
.findFirst()
.orElse(null);
assertNotNull(leafWithChildren);
assertEquals(leafWithChildren.getChildren().size(), 2);
LeafResponse leafWithSubChildren =
leafWithChildren.children.stream()
.filter(l -> l.name.equals("Leaf Children 1"))
.findFirst()
.orElse(null);
assertNotNull(leafWithSubChildren);
assertEquals(leafWithChildren.getChildren().size(), 2);
} 注意事项
- 确保 Mapstruct 的依赖已正确添加到项目中。
- Mapper 接口需要使用 @Mapper 注解进行标记。
- 可以使用 @Mapping 注解指定属性之间的映射关系,特别是当属性名称不一致时。
- 对于递归结构,需要定义多个 Mapper 接口,并确保它们能够相互调用。
- Mapstruct 会自动生成类型安全的映射代码,因此可以避免手动编写复杂的转换逻辑。
总结
通过使用 Mapstruct,我们可以轻松地处理 Java 中包含递归结构的对象的序列化。通过定义多个 Mapper 接口,并结合 @Mapping 注解,可以实现将具有嵌套 List 结构的实体类转换为对应的响应类,避免手动编写复杂的转换逻辑,提高开发效率和代码可维护性。 在处理复杂的数据结构转换时,Mapstruct 能够极大地简化开发流程,提高代码质量。









