相关文章推荐
拉风的小熊猫  ·  Django ...·  2 月前    · 
俊逸的竹笋  ·  kubernetes初始化报错Get ...·  1 年前    · 
叛逆的松鼠  ·  Harry Potter·  1 年前    · 

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

Hello Gunnar,

As you asked for my point of view, there's an important gap between Dozer and MapStruct in terms of features and it's the usage of custom mappers, referencing a concrete type that follows some interface to handle part of the mapping process.

This is useful when we need to map multiple source attributes to the same target attribute, e.g. to aggregate firstName and lastName into displayName.

Hi Nicolas,

Thanks for your input that's very much appreciated. Just to make sure I get right what you have in mind, is this about hooking in some custom "hand-written" mapping code? If so, there is support for this in the way that you can refer to other mappers via the uses attribute:

public class DateMapper {
    public String asString(Date date) {
        //custom mapping routine
@Mapper(uses=DateMapper.class)
public class CarMapper {
    CarDto carToCarDto(Car car);

Here, the generated implementation of carToCarToDto() will invoke the manually implemented method on DateMapper when mapping a car property from String to Date.

This wouldn't address the use case of merging several attributes into one though. One approach we have in mind for this is to support simple expressions like this:

@Mapper
public class CarMapper {
    @Mapping(target="displayName", source="firstName + lastName")
    CarDto carToCarDto(Car car);

I'm not sure about the implementation details, i.e. would that be actual Java code, just a very simplistic sub-set or maybe expression language. But I think it would be useful to have support for this in one way or the other.

Related to this there is also #14 which is about providing support for some kind of "pre-mapping" and "post-mapping" hooks. Using such a post-mapping hook, one might implement this sort of custom mapping code you describe.

Thanks again for your input Nicolas, it's very valuable to get feedback on what the real itches are here.

Please excuse me if I'm constantly referencing Dozer, but I have used it for some time and it's my scale...

So, back to the problem at hand: Dozer let you handle any part of the mapping tree with a custom mapper. For example, you can have a declarative mapper on the class, with implicit/declarative mappers on attributes save one. In this specific attribute, I could map from a list to a map. Basically, your previous DateMapper fills this use-case, if you can use a specific Mapper for attribute A and another for attribute B.

Providing multiple sources in the API could be nice, but you would probably be overwhelmed by crazy requirements like I want to upper-case this and that every other day. Maybe the pre/post processing could be handled this way.

Please excuse me if I'm constantly referencing Dozer, but I have used it for some time and it's my scale...

Hehe, sure, Dozer is a widely used solution, actually some issues with id led to the development of MapStruct.

Basically, your previous DateMapper fills this use-case, if you can use a specific Mapper for attribute A and another for attribute B.

Ah, got you now. Generally, when generating the mapping of a bean property from type X to type Y, MapStruct will a) look for other mapping methods with matching parameter and return type (either also generated or hand-written as in the DateMapper example) and generate an invocation of that method, and b) apply "implicit conversions" which it is able to generate itself (e.g. from numbers to strings).

The method resolution algorithm for a) is still in flux and we must find the right balance between safety, flexibility and comprehensibility. For cases where there are several candidate methods for mapping a property, we're considering to resolve that via "qualifiers":

public class DateMapper {
    @Named("long") //or maybe custom qualifier annotations, e.g. @LongFormat?
    public String asLongString(Date date) { ... }
    @Named("short")
    public String asShortString(Date date) { ... }
@Mapper(uses=DateMapper.class)
public class CarMapper {
    @Mapping(source="manufacturingDate", qualified="long")
    CarDto carToCarDto(Car car);

But that's still rather vague ideas at this point, maybe it would actually be simpler to just set the attribute using a post-mapping hook. Generally my thinking is that MapStruct should automate as much as possible the 80% of simple cases and get out of your way to do the difficult 20% from hand.

Going to close this one as I think it has been covered since then. There is support for

  • referencing custom mappers
  • combining several source props into one target prop (by means of expressions, which are inline Java statements atm., we are considering to support a "real" EL as well)
  • the qualifier feature I described above.
  • If needed, we can create follow-up issues for any remaining details. Thanks!