【问题标题】:Use entity method as MapStruct source使用实体方法作为 MapStruct 源
【发布时间】:2021-01-26 14:16:27
【问题描述】:

背景

我们目前正在使用六边形架构实现应用程序。我们的 REST API DTO 通过 MapStruct 映射到我们的实体。这工作正常。 (不过,如果 MapStruct 支持分层结构会更好。)

问题

但是,我们面临的问题可以通过以下示例进行最佳描述:

假设您有一个实体Person 来存储出生日期。现在,这 实体有一个可能称为int calculateAge() 的方法。 REST API 的PersonDto 将获得属性int age

现在,我们希望 MapStruct 为我们生成这个映射。我们的方法是尝试配置@Mapping(target = "age", ...) 使用int calculateAge() 方法作为源,但我们没有成功。 相信这可能是 MapStruct 的一个简单应用程序,但在搜索该主题数小时后仍未提出一个干净的解决方案,我们感到非常失望。

解决方案

我们发现了两种可行的解决方案,但(在我们看来)不是真正可维护的:

  1. 使用@Mapping(expression = "java(...)")
  2. 使用@AfterMapping对构造的DTO进行后期处理,并在注解的方法中实现所需的映射

问题

是否有更简洁的方法来实现我们的目标,可能类似于 @Mapping(sourceMethod = "calculateAge", target = "age)

【问题讨论】:

    标签: java mapstruct


    【解决方案1】:

    有没有更简洁的方法来实现我们的目标,可能看起来像这样......

    不,截至撰写此答案的 MapStruct 最新稳定版本 (1.4.1.Final) 还没有。您基本上有两种选择,这在很大程度上取决于您想要映射字段的确切内容和方式。我简要描述了每种解决方案适用于什么情况:

    1. 使用表达式的第一个解决方案引入了方法在注释中硬编码的问题。我只在不调用自定义方法(仅来自现有 Java API)的简单格式转换或计算的情况下更喜欢这种解决方案。无论如何,即使使用您提出的解决方案,它仍然是硬编码。语法是唯一改变的东西。在可维护性方面实际上没有区别:

      • @Mapping(target = "age", expression = "java(...)")        // current API
        
      • @Mapping(sourceMethod = "calculateAge", target = "age")   // hypothetical
        

      请随意request for 这样的功能。无论如何,此解决方案还需要在映射器 (@Mapper(imports = Another.class)) 以及“假设”中导入。

    2. 注释@AfterMapping 在更复杂的转换和计算的情况下很有用。它不像单个注释调用那样干净,实际上您仍然编写映射手动,但是它带来了对IDE在编译之前突出显示的调用方法的更多控制(至少您不需要额外的 IDE 特定插件)。如果我需要调用我的自定义方法和逻辑,我会选择这个解决方案。

    【讨论】:

    • 感谢您的回答。
    【解决方案2】:

    据我所知,Mapstruct 依赖于标准的 getter 和 setter。如果您想使用特定方法,那么 Mapstruct 确实可以使用 @qualifiers,但我认为该方法不能在实体中。正如您所提到的,根据我的经验,最好的解决方案是使用@AfterMapping。

    【讨论】:

      猜你喜欢
      • 2021-05-29
      • 2018-12-10
      • 1970-01-01
      • 2020-09-04
      • 2020-05-28
      • 2020-04-10
      • 1970-01-01
      • 2017-09-17
      • 2020-07-18
      相关资源
      最近更新 更多