Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MapStruct Mapper as Spring Framework Converter - idiomatic use possible?

Tags:

I'd like to combine MapStruct mappers with Spring's Conversion model. So I declare every Mapper interface as an extension of Spring's Converter:

@Mapper public interface CarMapper extends Converter<Car, CarDto> {         @Override     CarDto convert(Car car);     } 

I can then use the mapper beans by injecting the standard ConversionService:

class CarWarehouse {     @Autowired     private ConversionService conversionService;      ...      public CarDto getCarInformation(Car car) {         return conversionService.convert(car, CarDto.class);     } } 

This works nicely, but I'm wondering whether there's a way to avoid injecting some Mappers into others directly via the uses attribute. What I'd like to do is tell a Mapper to use the ConversionService for employing another mapper. However, since the ConversionService's convert method doesn't match MapStruct's standard pattern for a mapping method, the code generation plugin doesn't recognise that it can use the service when looking for a submapping. Basically, what I want to do is write

@Mapper(uses=ConversionService.class) public interface ParentMapper extends Converter<Parent, ParentDto> 

instead of

@Mapper(uses={ChildMapper1.class, ChildMapper2.class, ChildMapper3.class}) public interface ParentMapper extends Converter<Parent, ParentDto> 

Is there a way to achieve this?

Edit

Since it's been asked, let's say I've got a CarMapper defined as above, with the types Car and CarDto having an attribute wheel of type Wheel and WheelDto, respectively. Then I'd like to be able to define another Mapper like this:

@Mapper public interface WheelMapper extends Converter<Wheel, WheelDto> {         @Override     WheelDto convert(Wheel wheel);     } 

Right now, I'd have to add this Mapper explicitly:

@Mapper(uses = WheelMapper.class) public interface CarMapper extends Converter<Car, CarDto> 

Which would then give the generated CarMapperImpl an @Autowired member of type WheelMapper which would be called in order to map the attribute wheel.

However, what I'd like is that the generated code would look somewhat like this:

@Component public class CarMapperImpl implements CarMapper {     @Autowired     private ConversionService conversionService;     @Override     public CarDto convert(Car car) {         CarDto carDto = new CarDto();         carDto.setWheel(conversionService.convert(car.getWheel(), WheelDto.class);         return carDto;     } } 
like image 771
Ray Avatar asked Sep 24 '19 13:09

Ray


People also ask

What is MapStruct used for?

MapStruct is a code generator tool that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach. The generated mapping code uses plain method invocations and thus is fast, type-safe, and easy to understand.

How does MapStruct generate code?

MapStruct is an open-source Java-based code generator which creates code for mapping implementations. It uses annotation-processing to generate mapper class implementations during compilation and greatly reduces the amount of boilerplate code which would regularly be written by hand.


1 Answers

It's been more than a year since I asked this question, but now we've come up with an answer inside the MapStruct project itself - the MapStruct Spring Extensions project.

A CarMapper example is provided as an example within the project.

like image 71
Ray Avatar answered Oct 30 '22 20:10

Ray