Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
207 views
in Technique[技术] by (71.8m points)

java - 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. This works fine. (Though, it would be much nicer if MapStruct would have support for hierarchical structures.)

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. Now, this entity has a method which might be called int calculateAge(). The REST API's PersonDto will get an attribute int age.

Now, we want MapStruct to generate this mapping for us. Our approach was to try to configure @Mapping(target = "age", ...) to use the int calculateAge() method as source, but we did not succeed. 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.

Solutions

We found two solution approaches that work, but are (in our opinion) not really maintainable:

  1. Use @Mapping(expression = "java(...)")
  2. Use @AfterMapping to post process the constructed DTO and implement the required mappings in the annotated method

Question

Is there a cleaner way to achieve our goal, something which might look like this @Mapping(sourceMethod = "calculateAge", target = "age)?

question from:https://stackoverflow.com/questions/65903019/use-entity-method-as-mapstruct-source

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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. You have basically two choices which heavily depends what exactly and how you want to map the fields. 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). 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.

  2. The annotation @AfterMapping is useful in case of more complex transformations and calculations. 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). I'd go for this solution in case I need to call my custom methods and logics.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...