Best pattern for Mapstruct updater when a field can't be constructed/built without parameters

2 weeks ago 19
ARTICLE AD BOX

A simple mapper which also provides and 'update' mapper

@Mapper(componentModel = "spring", uses = "EngineMapper.class") public interface CarMapper { CarEntity carDtoToCarEntity(CarDto car); // Update mapper @InheritConfiguration(name = "carDtoToCarEntity") @BeanMapping( nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE , unmappedTargetPolicy = ReportingPolicy.IGNORE) void updateCarEntityFromCarDto(CarDto car, @MappingTarget CarEntity carEntity); }

Resulting generated update mapper looks something like this:

@Override void updateCarEntityFromCarDto(CarDto carDto, @MappingTarget CarEntity carEntity) { if ( carDto == null ) { return; } if( carDto.getEngine() != null ) { if ( carEntity.getEngine() == null ) { unit.setEngine( Engine.builder().build() ); // Notice this line } updateEngineEntityFromEngineDto( carDto.getEngine(), carEntity.getEngine() ); } ... }

But our Engine class has no public no-args constructor and has required fields with Lombock @NonNull So, the builder (with no args) with throw a NPE. I can add an Engine factory like this:

@ObjectFactory default EngineEntity createEngineEntity(EngineDto engineDto) { return engineDtoToEngineEntity( engineDto ); // Call the engine mapper }

And the generated update method now works:

@Override void updateCarEntityFromCarDto(CarDto carDto, @MappingTarget CarEntity carEntity) { if ( carDto == null ) { return; } if( carDto.getEngine() != null ) { if ( carEntity.getEngine() == null ) { unit.setEngine( createEngineEntity( carDto.getEngine() ) ); // Fixed } updateEngineEntityFromEngineDto( carDto.getEngine(), carEntity.getEngine() ); } ... }

However, this means that the engineDtoToEngineEntity will be called (to create/map the new EngineEntiy) and then that is followed by updateEngineEntityFromEngineDto which will needlessly run through logic to make sure it's updated (essentially doing the same thing twice). I couldn't figure out how to make the generated 'if' statement become an if/else statement to prevent the duplicate work. Is there a better pattern/solution?

Read Entire Article