【问题标题】:Map custom method mapper to Mapstruct将自定义方法映射器映射到 Mapstruct
【发布时间】:2018-07-09 08:48:33
【问题描述】:

我正在创建一个 poc,以便在我未来的项目中使用 Mapstruct。

现在我有一个问题,如何将自定义方法映射到特殊目标。

例如我有以下接口映射器:

@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;
    }

}

在代码中,您可以看到映射和一些带有其他映射的默认方法。如何在 Mapstruct 映射中使用这些方法,以便 mapstruct 使用这些方法填充字段中的值?

【问题讨论】:

标签: java mapstruct


【解决方案1】:

因为您有多个返回相同类型的默认方法。您需要使用Mapping method selection based on qualifiers

这意味着您需要按以下格式编写映射器:

@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
    }
}

一些重要说明:

  • 您需要使用 MapStruct 包中的@Named
  • source中也可以指定方法的参数名称
  • qualifiedByName 中您需要指定您在@Named 中写入的值

我强烈建议不要对如此复杂的事情使用表达式。正确更难,维护也更困难

【讨论】:

  • 我尝试从映射中删除源部分,但没有成功。我的问题是我们可以从映射和方法参数中跳过源参数吗?
  • 这是@NamedMapStruct documentation 更直接的用法。对于那个上下文以及这个问题的超级有用的答案,太棒了!
【解决方案2】:

最简单的方法是使用强大的 mapstruct @AfterMapping annotation。例如

@AfterMapping
public void treatAdditional(User user, @MappingTarget StudentSkillsTo studentSkillsTo) {
    System.out.println("After mapping!");
}

【讨论】:

    【解决方案3】:

    Mapstruct 可以使用类似的结构:

    @Mapping(target = "name", expression = "java(user.getName() != null " +
            " ? user.getName() : "DefaultName")")
    

    表达式可以包含java上的任何结构 例如

     item.getItemsOnDetailedLocations()
    .iterator().next().getLocation().getLocation();
    

    如果方法很大,那么值得将它带到另一个服务并以这种方式调用

    【讨论】:

    • 我试过@Mapping(target = "location", expression = "java(item.getItemsOnDetailedLocations().iterator().next().getLocation().getLocation())"), @ Mapping(target = "bintype", expression = "java(item.getItemsOnDetailedLocations().iterator().next().getBinType())") 但没有任何运气。字段仍然为空
    • 你的方法,应该同时使用两个对象。 void itemToDto(@MappingTarget ItemViewModel itemViewModel, item);
    【解决方案4】:

    你可以像下面这样简单地使用它们

    @Mapping( target="/*Enter targetFieldName*/", expression="java( /default method which calculates target field/" )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 2019-07-04
      • 2021-12-04
      • 2021-02-17
      • 1970-01-01
      相关资源
      最近更新 更多