Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mapstruct - Propagate parent field value to collection of nested objects

Tags:

java

mapstruct

Is it possible to propagate value form a parent object to collection of nested objects? For example

Source DTO classes

class CarDTO {
  private String name;
  private long userId;
  private Set<WheelDto> wheels; 
};

class WheelDto {
  private String name;
}

Target entity classes

class Car {
  private String name;
  private long userId;
  private Set<Wheel> wheels; 
};

class Wheel {
  private String name;
  private long lastUserId;
}

As you could see I do not have lastUserId on WheelDto, hence I would like to map userId from CarDto to lastUserId on WheelDto on each object in a wheels collection I tried

@Mapping(target = "wheels.lastUserId", source = "userId") 

but no luck

like image 226
antohoho Avatar asked Dec 21 '18 02:12

antohoho


1 Answers

Currently it is not possible to pass a property. However, you could solve this via @AfterMapping and / or @Context.

Update Wheel after Car mapping

This would though mean that you would need to iterate twice over the Wheel. It can look like

@Mapper
public interface CarMapper {

    Car map(CarDto carDto);

    @AfterMapping
    default void afterCarMapping(@MappingTarget Car car, CarDto carDto) {
        car.getWheels().forEach(wheel -> wheel.setLastUserId(carDto.getUserId()));
    }
}

Pass @Context while mapping wheel to have state during the mapping

If you want to iterate only once through the Wheel then you can pass a @Context object that would get the userId from the CarDto before mapping the car and then set it on the Wheel in an after mapping. This mapper can look like:

@Mapper
public interface CarMapper {

    Car map(CarDto carDto, @Context CarContext context);

    Wheel map(WheelDto wheelDto, @Context CarContext context);

}

public class CarContext {

    private String lastUserId;

    @BeforeMapping
    public void beforeCarMapping(CarDto carDto) {
        this.lastUserId = carDto.getUserId();
    }

    @AfterMapping
    public void afterWheelMapping(@MappingTarget Wheel wheel) {
        wheel.setLastUserId(lastUserId);
    }

}

The CarContext would be passed to the wheel mapping method.

like image 88
Filip Avatar answered Oct 09 '22 22:10

Filip