web-dev-qa-db-fra.com

Mapper une méthode personnalisée mappeur à Mapstruct

Je crée un poc pour utiliser Mapstruct dans mes projets futurs.

Maintenant, j'ai une question: comment mapper des méthodes personnalisées sur une cible particulière.

Par exemple, j'ai l'interface suivante mappeur:

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

}

Dans le code, vous pouvez voir le mappage et certaines méthodes par défaut avec d'autres mappages. Comment puis-je utiliser ces méthodes dans les mappages Mapstruct afin que mapstruct les utilise pour renseigner des valeurs dans les champs?

3
JimmyD

Comme vous avez plusieurs méthodes par défaut qui retournent le même type. Vous devrez utiliser La sélection de la méthode de mappage en fonction des qualificateurs .

Cela signifie que vous devez écrire votre mappeur au format suivant:

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

Quelques notes importantes:

  • Vous devez utiliser @Named à partir du package MapStruct
  • Dans source, vous pouvez également spécifier le nom du paramètre de la méthode.
  • Dans qualifiedByName, vous devez spécifier la valeur que vous avez écrite dans @Named

Je déconseille fortement d'utiliser des expressions pour des choses aussi compliquées. Il est beaucoup plus difficile de le faire correctement et plus difficile de maintenir

8
Filip

Mapstruct peut utiliser des constructions similaires:

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

une expression peut inclure n'importe quelle construction sur Java e.g

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

si la méthode est volumineuse, cela vaut la peine d’utiliser un autre service et d’appeler de cette façon

1
Redbore

Vous pouvez simplement les utiliser comme suit

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