-
-
Notifications
You must be signed in to change notification settings - Fork 947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to globally configure @Mapping for properties in reused super classes #168
Comments
For this there is #72 already. |
Oh, right. 😀 |
As #72 is now resolved, I've updated this issue to something that builds upon it and fits my requirements. @gunnarmorling, @sjaakd: what do you think? |
Btw, Sjaak already mentioned somewhere the idea to specify a global "dictionary" for source-to-target property names, this proposal could be a solution for this as well. |
We are set to go for this. We have a However, I also think we need to be careful with automation. From my own experience, sometimes unpredictable behavior is occurring because Mapstruct is using Next, I experienced last friday the hard-way (while integrating beta2), I did need to copy a lot of mappings due to reverse mapping. I'll open a new issue for that. |
@sjaakd Do you have an example for this? Predictablility is one of the core values in MapStruct, so if there are issues around this, we need to look into ways of improving this. Built-in methods and type conversions should only be used if no other hand-written (or generated) method is found. Are there situations where this is not the case? |
No.. The mechanism is clear. And after all: you can always check the generated code (so there you have an implicit logging mechanism). However, I try to build a library of reusable [GML](http://www.opengeospatial.org/standards/gml specific) hand-written mappers, typically related GIS applications. Were these fail, I switch to more domain specific HW mappers. Typically I have a list of used mappers constituting both in a mapper. If I - for instance - forget to include a domain specific mapper, I'm surprised in how MapStruct uses type conversions and built-in methods to select a GML mapper. Usually these are fixed quite fast. I know were to look. But I noticed that other users in my surrounding sometimes find it harder to fix it. I'm not such a good documentation reader myself. You know, don't read the manual of a new device, just try :) . So one idea could be to include some logging on how MapStruct came to the selection of a mapping method or type conversion. This would than also include which mapping is applied (global / local / implicit / reverse), which selection rules are used: (direct, used, built-in, type-conversion) and which configuration option is used (e.g. CollectionMappingStrategy). |
@agudian What are the use cases for this feature of global mappings? I feel it adds quite some complexity and makes mapper interfaces potentially much harder to grasp. E.g. couldn't the ignored audit trail property just be solved by not having that attribute in the target objects? |
Why didn't I think of that? 😉 No, seriously: we have some properties in our base entity types that are handled and populated / updated only by entity listeners (audit stuff, when was something last updated by whom and so on). On the DTO side, we have a UUID in the base class that has no representation in the entities. We need that UUID in the DTO for objects created on the client side that don't yet have a representing entity instance, but for which we need some identity still: for change detection, for visualizing validation errors on the right rows in a table, etc. So for me personally, I'm only interested in ignoring target properties for certain base types. This was the easiest way to implement it (easy in terms of coding - I spent the most time with thinking about the unit test 😉). |
I have similar problems: also need to populate an id, which are not in my entities but are in my JAXB objects. I use an expression for that (UUID). So it would be nice if that is supported as well. |
Hey guys.. I finally had some time to look at this in more detail and like to move forward with this one. Especially the @gunnarmorling : do you think this is ready to be merged? |
@gunnarmorling : I've quite some use cases for this as well. For instance, I've got a lot of (JAXB) base classes that always need to be populated, with the same constants and expressions (e.g. for ID generation). I spent last saturday getting Netbeans to work with giving in-IDE feedback, just as is possible with Eclipse and I like it a lot. This takes a way a lot of the pain I mentioned before. I still think its a good idea to add some logging in MapStruct, for instance triggered by the --debug option in Maven somehow. |
Voting for this feature. As of 1.0.0.Beta3 it is no longer possible to get update- methods generated from a |
@agudian, I've been thinking a bit more about this. There is basically two things I'm concerned about with the proposed approach:
So what would you think about re-using
This would address the concerns above:
We'd also re-use an existing construct rather than defining a new one. Now some downsides:
All in all, that approach seems beneficial to me due to its regularity, explicitness and re-use of existing constructs. WDYT? |
I guess that can be done by using Another advantage of the inheritance approach is that it avoids any mismatches between conflicting global mappings for the same types as a method can only its configuration from exactly one other method. |
Or, we take methods defined on the conflig class into account for this purpose. The nice thing about that is that it doesn't really change the scope of |
Drums.. TADA.. You've got a strange form of favorites 😄.. Anyway. To list the remaining topics to be solved:
|
Ok then, I've placed my bet. Let the BDOL decide... 😉 On 2. I'm kind of out - I also have a feeling that re-using InheritConfiguraiton and InheritReverseConfiguration could cause some trouble/inconsistencies and that we might better add some new and specific annotation there. But that's really just a feeling based on no hands-on experience with that stuff. You two are much deeper into that, so you decide, I'll implement 😀
Something else missing? |
Yes, ok, that make sense. Have an option on |
Where would one use that? As I see it, all the method definitions on the There are two cases:
|
Regaring having a specific |
Generally I prefer to re-use (and possibly enhance/generify) existing annotations and constructs rather than adding new ones. But if a construct is too generic, it often gets too verbose to use it. Thus I think it's fine to have the explicit But for the case of inheriting base configurations re-using |
Ok. Lets go ahead and try. I do think we need to think a bit more on ruling. Examples: I want to avoid relations as A -> B -> A . So 'A' inherits from 'B' inherits from 'A' again. I avoided this by simply not allowing A to inherit its configuration from B if B itself inherits also from something. I think we need to fine-tune that.
If we can work the above out, then we're there.
That's good. I think we can close that discussion (in my mind this was still an open end somewhere 😄 ) ). |
+1 This situation must be detected and prohibited. It's easy when Also some ordering must be applied (in case there is a mapping method for super-types and another one for super-super types).
Why would that be needed? Couldn't one base configuration method inherit the config from another one?
Could you give an example for the situation you have in mind? |
Regarding the referencing of methods in the mapper config via |
Ah.. I think you already know what situation i have in mind 😄 . But this is why I had a special annotation |
You mean prefer the "local" class over the
Isn't that overkill? There are only 2 options, right "local" or |
I've been thinking a bit more on this. Perhaps we should use an enum iso the class. Or do you want to open up the possibility as well to refer to entirely different mappers? So: @Target( ElementType.METHOD )
@Retention( RetentionPolicy.SOURCE )
public @interface InheritConfiguration {
public enum Scope { LOCAL, MAPPER_CONFIG, BOTH }
String name() default "";
boolean inverse() default false;
Scope scope() default Scope.BOTH;
} Note: *. *. @agudian: Have you thought about update / create methods (in the |
Yes, I think some flexibility may be beneficial here. Not necessarily for mapper classes (at least for now), but I could imagine cascades of global config classes (i.e. one global config class extending another one). |
Ah, do you prefer that flag now? Didn't we agree on the separate annotation being nicer to read? |
I was exploring the possibility 😄 .. Actually, the same arguments as you apply to having separate annotations for Anyway.. Perhaps we should leave it up to @agudian at this point. We have discussed it sufficiently (at least I think), and perhaps we should see what implementation yields. WDYT? |
Yes, I think the general direction is clear, so I think we can can continue (or just finish ;) ) the discussion once Andreas has updated the PR based on our latest line of thought. Being able to specify base mapping methods in config classes is the key piece which was missing before. |
… @MapperConfig-annotated type, either automatically when all method types match, or explicitly using @InheritConfiguration.
… @MapperConfig-annotated type, either automatically when all method types match, or explicitly using @InheritConfiguration.
… @MapperConfig-annotated type, either automatically when all method types match, or explicitly using @InheritConfiguration.
…onfusion with @MapperConfig
@agudian The PR is merged. I'll leave the issue open until the doc update is there. Thx! |
…as they now need to be read from other classes as well
Doc update pushed. |
With #72 being resolved now, we need some means to allow ignoring certain properties from being mapped / reported as unmapped on a global scope.
I could think of something along the following lines (with much room for improvement for the naming):
That annotation (or a multiple of it) would be allowed at mapper level (e.g. in
@Mapper
) and in the@MapperConfig
annotation.sourceType
andtargetType
would be optional, and the specified@Mapping
configuration would be applied for each mapping method that has source / target types that fit (as in "assignable from").The text was updated successfully, but these errors were encountered: