user3529850
user3529850

Reputation: 976

Mapstruct 'aftermapping' not called

The problem is that, methods annotated with @AfterMapping are not called at all. From the testToEntityMapping it goes to toEntity method but it doesn't call any of the toEntityAfterMapping() methods. Why ? Is it possible ? how can I achieve that using MapStruct ?

(Here I have prepared a scenario that is meaningless but it fully captures the essence of my question)
Entity:

public class Ford {
    private String color;
    private String market;
    private int totalWidth;

    //getters and setters omitted for brevity
}

Dtos:

public abstract class FordDto {
    public String market;
    public String color;

    //getters and setters omitted for brevity
}

public class EuropeanFordDto extends FordDto{
    private int totalWidth;

    public int getTotalWidth() {
        return totalWidth + 2;//"+2" for EU market
    }
    //setter omitted for brevity
}

public class AmericanFordDto extends FordDto{
    private int totalWidth;

    public int getTotalWidth() {
        return totalWidth + 1;//"+1" for US market
    }

    //setter omitted for brevity
}

Mappers:

public abstract class FordMapper<D extends FordDto> {
    public Ford toEntity(D dto) {

        /* fill in fields common to both ford versions */

        final Ford ford = new Ford();

        ford.setColor(dto.getColor());
        ford.setMarket(dto.getMarket());

        return ford;
    }
}
@Mapper(componentModel = "spring")
public abstract class EuropeanFordMapper extends FordMapper<EuropeanFordDto> {

    @AfterMapping
    public void toEntityAfterMapping(final EuropeanFordDto dto, @MappingTarget final Ford entity) {

        /* Fill in fields related to european version of the ford */

        entity.setTotalWidth(dto.getTotalWidth());
    }
}
@Mapper(componentModel = "spring")
public abstract class AmericanFordMapper extends FordMapper<AmericanFordDto> {

    @AfterMapping
    public void toEntityAfterMapping(final AmericanFordDto dto, @MappingTarget final Ford entity) {

        /* Fill in fields related to american version of the ford */

        entity.setTotalWidth(dto.getTotalWidth());
    }
}

Service:

@Service
public class CarService {

    @Autowired
    private AmericanFordMapper americanFordMapper;
    @Autowired
    private EuropeanFordMapper europeanFordMapper;

    public void testToEntityMapping(final FordDto dto) {

        if (dto instanceof AmericanFordDto) {
            americanFordMapper.toEntity((AmericanFordDto) dto);
        } else {
            europeanFordMapper.toEntity((EuropeanFordDto) dto);
        }
    }
}

Upvotes: 8

Views: 12763

Answers (2)

Eduard Streltsov
Eduard Streltsov

Reputation: 1956

My solution to the same problem was that I forgot to add 'default' keyword to my @AfterMapping method (I used interface). After that method appeared in generated code.

And don't forget to run mvn/gradle clean and compile after making changes.

Upvotes: 2

user3529850
user3529850

Reputation: 976

Ok, it was simpler than I thought it is.

public interface FordMapper<D extends FordDto> {
    
    @Mapping(target = "totalWidth", ignore=true)
    public abstract Ford toEntity(D dto);
}

you can even peek in the implementation that is in toEntity() method, there is a call to toEntityAfterMapping(), thus everything is correct and in accordance with our desired result.

Upvotes: 1

Related Questions