Reputation: 976
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
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
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