简体   繁体   English

使用实体方法作为 MapStruct 源

[英]Use entity method as MapStruct source

Background背景

We are currently implementing an application using hexagonal architecture.我们目前正在使用六边形架构实现应用程序。 Our REST API DTOs are mapped to our entities via MapStruct.我们的 REST API DTO 通过 MapStruct 映射到我们的实体。 This works fine.这工作正常。 (Though, it would be much nicer if MapStruct would have support for hierarchical structures.) (不过,如果 MapStruct 支持分层结构会更好。)

Problem问题

However, we are facing a problem which is best described by the following example:但是,我们面临的问题可以通过以下示例进行最佳描述:

Consider you have an entity Person that stores the date of birth.假设您有一个存储出生日期的实体Person Now, this entity has a method which might be called int calculateAge() .现在,这个实体有一个可以称为int calculateAge()的方法。 The REST API's PersonDto will get an attribute int age . REST API 的PersonDto将获得一个属性int age

Now, we want MapStruct to generate this mapping for us.现在,我们希望 MapStruct 为我们生成这个映射。 Our approach was to try to configure @Mapping(target = "age", ...) to use the int calculateAge() method as source, but we did not succeed.我们的方法是尝试配置@Mapping(target = "age", ...)以使用int calculateAge()方法作为源,但我们没有成功。 Believing this might be a straightforward application of MapStruct, we were quite disappointed to not come up with a clean solution after searching on this topic for hours.相信这可能是 MapStruct 的一个简单应用程序,在搜索了几个小时后,我们对没有提出一个干净的解决方案感到非常失望。

Solutions解决方案

We found two solution approaches that work, but are (in our opinion) not really maintainable:我们发现了两种可行的解决方案,但(在我们看来)不是真正可维护的:

  1. Use @Mapping(expression = "java(...)")使用@Mapping(expression = "java(...)")
  2. Use @AfterMapping to post process the constructed DTO and implement the required mappings in the annotated method使用@AfterMapping对构造的DTO进行后期处理,并在注解的方法中实现所需的映射

Question问题

Is there a cleaner way to achieve our goal, something which might look like this @Mapping(sourceMethod = "calculateAge", target = "age) ?有没有更简洁的方法来实现我们的目标,可能看起来像这样@Mapping(sourceMethod = "calculateAge", target = "age)

Is there a cleaner way to achieve our goal, something which might look like this...有没有更清洁的方法来实现我们的目标,可能看起来像这样......

No, there isn't as of the MapStruct latest stable version ( 1.4.1.Final ) of time of writing this answer.不,截至撰写此答案的 MapStruct 最新稳定版本( 1.4.1.Final )还没有。 You have basically two choices which heavily depends what exactly and how you want to map the fields.您基本上有两个选择,这在很大程度上取决于您想要 map 字段的确切内容和方式。 I describe shortly in what case each solution is suitable for:我简要描述了每种解决方案适用于什么情况:

  1. The first solution using expression introduces the problem the methods are hardcoded in the annotation.使用表达式的第一个解决方案引入了方法在注释中硬编码的问题。 I prefer this solution only in the case of simple format conversions or calculations without calling a custom method (only from the existing Java API).我只在不调用自定义方法(仅来自现有的 Java API 的情况下)的简单格式转换或计算的情况下更喜欢此解决方案。 Anyway, even with your proposed solution it would be still hardcoded .无论如何,即使使用您提出的解决方案,它仍然是硬编码的。 The syntax is the only thing that changes.语法是唯一改变的东西。 There is effectively no difference in terms of maintainability:在可维护性方面实际上没有区别:

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

    Feel free to request for such feature.随时请求此类功能。 This solution in any case also requires imports within the mapper ( @Mapper(imports = Another.class) ) as well as the "hypothetical" one.在任何情况下,此解决方案还需要在映射器( @Mapper(imports = Another.class) )以及“假设的”映射器中导入。

  2. The annotation @AfterMapping is useful in case of more complex transformations and calculations.注释@AfterMapping在更复杂的转换和计算的情况下很有用。 It's not as clean as a single annotation call and in fact you still write the mapping manually , however, it brings more control over the called methods which the IDE highlights before the compilation (at least you don't need an additional IDE-specific plugin).它不像单个注释调用那样干净,实际上您仍然手动编写映射,但是,它可以更好地控制 IDE 在编译之前突出显示的调用方法(至少您不需要额外的特定于 IDE 的插件)。 I'd go for this solution in case I need to call my custom methods and logics.如果我需要调用我的自定义方法和逻辑,我会为此解决方案使用 go。

From what I've seen, Mapstruct relies on standard getters and setters.据我所知,Mapstruct 依赖于标准的 getter 和 setter。 If you want to use a specific method then Mapstruct does work with @qualifiers, but I don't think the method can be in the entity.如果您想使用特定方法,那么 Mapstruct 确实可以使用 @qualifiers,但我认为该方法不能在实体中。 From my experience the best solution is to use @AfterMapping, as you mentioned.正如您所提到的,根据我的经验,最好的解决方案是使用@AfterMapping。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM