返回

MapStruct对象映射常见问题和最佳实践

java

使用 MapStruct 进行不同数据源的对象映射

在软件开发中,我们需要在不同的数据对象之间进行转换。MapStruct 是一个代码生成库,可以自动生成对象之间的映射实现。

问题

我们有一个场景,需要将 Source 对象映射到 Target 对象。Source 对象有一个字符串字段 str3,而 Target 对象有两个字符串字段 (str1str2) 和一个嵌套对象 anotherObjanotherObj 对象也有两个字符串字段 (str3str4)。

最初的 MapStruct 映射如下:

@Mapping(target = "anotherObj", source = "request", qualifiedByName = "mapAnotherObjToSource")
@Mapping(target = "anotherObj.str4", source = "str4")
Target convert(Source request, String str4);

然而,执行映射时,我们遇到了一个错误:

Java: No read accessor found for property anotherObj in target type.

错误分析

错误表明 MapStruct 找不到目标类型 TargetanotherObj 属性的读取访问器。这是因为我们没有为 anotherObj 属性定义 getter 方法。

解决方案

1. 添加 getter 方法

@Getter
public class Target {
  public String str1;
  public String str2;
  public AnotherObj anotherObj;
}

2. 使用 @AfterMapping 方法

除了添加 getter 方法,我们还可以使用 @AfterMapping 方法来处理映射后的自定义逻辑。@AfterMapping 方法将在映射过程完成后调用。

@AfterMapping
default void handleStr4(@MappingTarget Target target, Source source, String str4) {
  if (target.getAnotherObj() != null) {
    target.getAnotherObj().setStr4(str4);
  }
}

结论

在使用 MapStruct 进行对象映射时,重要的是确保为所有目标属性定义 getter 方法。此外,@AfterMapping 方法可以让你在映射过程后执行自定义逻辑。遵循这些准则,我们可以创建健壮且可维护的对象映射实现。

常见问题解答

1. 什么时候使用 MapStruct?

  • 当需要在不同的数据对象之间进行转换时。
  • 当需要创建可维护且可扩展的映射实现时。

2. 如何添加 getter 方法?

  • 使用注解 @Getter(Java 9+)或手动定义 getter 方法。

3. 什么时候使用 @AfterMapping 方法?

  • 当需要在映射过程后执行自定义逻辑时。
  • 当需要设置默认值或进行其他计算时。

4. 如何避免目标类型中属性没有读取访问器的错误?

  • 确保为所有目标属性定义 getter 方法。

5. 如何使用 @Mapping 注解进行更细粒度的控制?

  • 使用 @Mapping 注解的属性参数和方法参数可以配置映射的细节。
  • 可以指定转换器、源属性、目标属性、忽略字段和更多选项。