Extending and reusing mappers

751 views
Skip to first unread message

Igors

unread,
Mar 23, 2017, 6:17:34 AM3/23/17
to mapstruct-users
Hi!

First of all thank you for the great tool!
Please advise on solving the following problem in a CDI (Contexts & Dependency injection) environment:
I have MapperA which prepares TargetA and has some custom logic defined. I need a MapperB who will do additional custom logic for TargetA (basically transform TargetA to TargetB).
public class SourceA {
   
private Integer amount;
   
private Date date;
   
// Getters and setters.
}

public class TargetA {
   
private Integer amount;
   
private Date date;
   
// Formatting logic done by mapperB.
    private String amountFormatted;
   
private String dateFormatted;
   // Getters and setters.
}

public class TargetB {
   
private String amountFormatted;
   
private String dateFormatted;
   
// Getters and setters.
}

@Mapper
public abstract class MapperA {

   
public abstract TargetA sourceToTarget(SourceA sourceA);

   
@AfterMapping
    void logic1(SourceA sourceA, @MappingTarget targetA) {...}

   
@AfterMapping
   void logic2(SourceA sourceA, @MappingTarget targetA) {...}
}

// 1. This way I have ambiguous dependency exception when injecting MapperA, e.g.
// @Inject MapperA mapperA;
// because of mapper implementations
MapperAImpl, MapperBImpl.
// I tried using @Qualifier, but it is not added for implementation classes.
@Mapper(uses = {AmountMapper.class, DateMapper.class})
public abstract class MapperB extends MapperA {

   
@AfterMapping
    void logicFormatted(@MappingTarget targetA) {
        targetA
.amountFormatted = amountFormat();
        targetA.dateFormatted = dateFormat();
   }
}

// 2. This way all the custom logic for MapperB is applied before MapperA has prepared data with it's custom logic and each mapper creates own TargetA object.
@Mapper(uses = MapperA.class)
public abstract class MapperB {

   
public abstract TargetA sourceToTarget(SourceA sourceA);

   
@AfterMapping
    void logicFormatted(SourceA sourceA, @MappingTarget targetA) {...}
}

I think that both of these approaches are wrong.
Thank you!

Andreas Gudian

unread,
Mar 26, 2017, 1:07:54 PM3/26/17
to Igors, mapstruct-users
Hi Igors,

I would move the the methods logic1 and logic2 into a seperate class, add it to MapperA via @Mapper#uses and then move logicFormatted into another class as well. In MapperB, you can then add the required classes with @Mapper#uses as well: MapperA (if you actually need it), the class containing logic1 and logic2, and after that the class containing logicFormatted. Then the call order should be as you intend it to be.

However, that feels a bit funny and is probably not very expressive. How about using plain CDI Decorators around the mapper? Or use the MapStruct Decorator support?

Andreas

--
You received this message because you are subscribed to the Google Groups "mapstruct-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mapstruct-users+unsubscribe@googlegroups.com.
To post to this group, send email to mapstruct-users@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages