Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map custom method mapper to Mapstruct

Tags:

java

mapstruct

I'm creating a poc for using Mapstruct in my future projects.

Now I have one question how to map custom methods to a special target.

For example I have following interface mapper:

@Mapper public interface ItemMapper {      static ItemMapper INSTANCE = Mappers.getMapper(ItemMapper.class);      @Mappings({ @Mapping(source = "number", target = "itemnumber"),             @Mapping(source = "description", target = "description"),             @Mapping(source = "itemClass.name", target = "ic"), @Mapping(source = "optionPart", target = "option"),             @Mapping(source = "plannerCode.code", target = "plannercode"),             @Mapping(source = "plannerCode.name", target = "planner"),             @Mapping(source = "vendor.buyerCode.name", target = "buyer"),             @Mapping(source = "vendor.buyerCode.code", target = "buyerCode"),             @Mapping(source = "vendor.number", target = "vendor"),             @Mapping(source = "vendor.name", target = "vendorName"), @Mapping(source = "pcsItem", target = "pcs"),             @Mapping(source = "specialColourVariant", target = "specialColors"),             @Mapping(source = "qtyBufferGreen", target = "greenLine"),             @Mapping(source = "qtyBufferRed", target = "redine"), @Mapping(source = "leadtime", target = "leadTime"),             @Mapping(source = "qtyStock", target = "stockAC"),             @Mapping(source = "qtyStockSupplier", target = "stockSupplier"),             @Mapping(source = "qtyPurchaseOrder", target = "qtyPo"),             @Mapping(source = "qtyShopOrder", target = "qtySo"),             @Mapping(source = "qtyFirmPlannedOrder", target = "qtyFpo"),             @Mapping(source = "qtyForecast", target = "qtyForecast"),             @Mapping(source = "standardCost", target = "stdCost"),             @Mapping(source = "itemCategory.name", target = "category") })     ItemViewModel itemToDto(Item item);      default String locationToLocationDto(Item item) {         return item.getItemsOnDetailedLocations().iterator().next().getLocation().getLocation();     }      default double locationToBinType(Item item) {         return item.getItemsOnDetailedLocations().iterator().next().getBinType();     }      default double itemToLotsize(Item item) {         double lotSize = 0;         if (item.getLotsize() != null) {             lotSize = item.getLotsize();         } else if (item.getItemsOnDetailedLocations() != null && !item.getItemsOnDetailedLocations().isEmpty()) {             ItemsOnDetailedLocation location = item.getItemsOnDetailedLocations().iterator().next();             lotSize = location.getLotSize();         } else {             lotSize = 0.0;         }         return lotSize;     }      default double stockRails(Item item) {         double value = 0;         for (ItemsOnDetailedLocation detailedLocation : item.getItemsOnDetailedLocations()) {              if (detailedLocation.getId().getSource().equals("RAILS")) {                  long lotSize2 = detailedLocation.getLotSize();                 long binInStock = detailedLocation.getBinInStock();                  if (binInStock != 0) {                      value += lotSize2 * (binInStock - 0.5);                 }             }          }          return value;     }  } 

In the code you can see the mapping and some default methods with other mapping in it. How can I use those methods in the Mapstruct mappings so that mapstruct uses those methods to fillin values in the fields?

like image 907
JimmyD Avatar asked Jan 30 '18 12:01

JimmyD


People also ask

How do I map a MapStruct list?

Using Mapstruct we can map list in similar fashion as we map primitives. To get a list of objects, we should provide a mapper method which can map an object.

What is MapStruct AfterMapping?

Annotation Type AfterMappingMarks a method to be invoked at the end of a generated mapping method, right before the last return statement of the mapping method. The method can be implemented in an abstract mapper class, be declared in a type (class or interface) referenced in Mapper.

Does MapStruct use reflection?

During compilation, MapStruct will generate an implementation of this interface. This implementation uses plain Java method invocations for mapping between source and target objects, i.e. no reflection or similar.

What is the use of Mapper interface?

This method is used to clear and remove all of the elements or mappings from a specified Map collection. This method is used to check whether a particular key is being mapped into the Map or not. It takes the key element as a parameter and returns True if that element is mapped in the map.


2 Answers

As you have multiple default methods that return the same type. You would need to use Mapping method selection based on qualifiers.

What this means is that you would need to write your mapper in the following format:

@Mapper public interface ItemMapper {      // Omitting other mappings for clarity     @Mapping(source = "item", target = "locationDto", qualifiedByName = "locationDto")     @Mapping(source = "item", target = "binType", qualifiedByName = "binType")     @Mapping(source = "item", target = "lotSize", qualifiedByName = "lotSize")     @Mapping(source = "item", target = "stockRails", qualifiedByName = "stockRails")     ItemViewModel itemToDto(Item item);      @Named("locationDto")     default String locationToLocationDto(Item item) {         //Omitting implementation     }      @Named("binType")     default double locationToBinType(Item item) {         //Omitting implementation     }      @Named("lotSize")     default double itemToLotsize(Item item) {         //Omitting implementation     }      @Named("stockRails")     default double stockRails(Item item) {         //Omitting implementation     } } 

Some important notes:

  • You need to use @Named from the MapStruct package
  • In source you can also specify the name of the parameter of the method
  • In qualifiedByName you need to specify the value that you have written in @Named

I would strongly advise against using expressions for such complicated things. It is much more difficult to get it correct and it is more difficult for maintaining

like image 185
Filip Avatar answered Sep 30 '22 18:09

Filip


Simplest way is using powerfull mapstruct @AfterMapping annotation. E.g.

@AfterMapping public void treatAdditional(User user, @MappingTarget StudentSkillsTo studentSkillsTo) {     System.out.println("After mapping!"); } 
like image 26
Grigory Kislin Avatar answered Sep 30 '22 18:09

Grigory Kislin