Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MapStruct add a new calculated field to the dto

I'm trying to map an entity Order to a OrderDTO using MapStruct. I want to add to OrderDTO a new field total, this field is not available in the original entity Order and should be calculated using the information available in the Order (order entries price, quantity, taxes...). I created a new field total in the OrderDTO and I'm trying to map it by adding a default method to the mapper interface:

public interface OrderMapper {

    ...

    default BigDecimal orderToTotal(Order order){
        return logicToCalculateTotal();
    }
}

When I lunch the build MapStruct launch the error

Unmapped target property: "total".

Any idea how to solve this problem?

Thanks

like image 426
Roberto Avatar asked Aug 04 '17 07:08

Roberto


People also ask

How do I map a MapStruct collection?

In general, mapping collections with MapStruct works the same way as for simple types. Basically, we have to create a simple interface or abstract class, and declare the mapping methods. Based on our declarations, MapStruct will generate the mapping code automatically.

What is componentModel in MapStruct?

Enclosing class: MappingConstants public static final class MappingConstants.ComponentModel extends Object. Specifies the component model constants to which the generated mapper should adhere. It can be used with the annotation Mapper.componentModel() or MapperConfig.componentModel()

Does MapStruct work with Lombok?

AST modifications are not foreseen by Java annotation processing API, so quite some trickery was required within Lombok as well as MapStruct to make both of them work together. Essentially, MapStruct will wait until Lombok has done all its amendments before generating mapper classes for Lombok-enhanced beans.

How do I set default value in MapStruct?

Java Prime Pack Using Mapstruct we can pass the default value in case source property is null using defaultValue attribute of @Mapping annotation.


1 Answers

There are multiple way to achieve what you need. The first way is to use @AfterMapping or @BeforeMapping. If you go with this your code will look like:

public interface OrderMapper {

    @Mapping(target = "total", ignore = true) // Needed so the warning does not shown, it is mapped in calculateTotal
    OrderDto map(Order order);

    @AfterMapping // or @BeforeMapping
    default void calculateTotal(Order order, @MappingTarget OrderDto dto) {
        dto.setTotal(logicToCalculateTotal());
    }
}

The alternative approach would be to do like you started, but you have to say that total is mapped from the Order.

Your mapper in the alternative approach would be:

public interface OrderMapper {

    @Mapping(target = "total", source = "order")// the source should be equal to the property name
    OrderDto map(Order order);

    default BigDecimal orderToTotal(Order order) {
        return logicToCalculateTotal();
    }
}
like image 130
Filip Avatar answered Sep 23 '22 13:09

Filip