Support generic `@Context`
Use case
Consider the following example mapstruct-jpa-child-parent but with generic JpaContext:
@Data class ParentDto { ChildDto child; } @Data class ChildDto { ParentDto parent; } @Data class ParentEntity { ChildEntity child; } public interface ParentRelation<T> { void setChildToParent(T parent); } @Data class ChildEntity implements ParentRelation<ParentEntity> { ParentEntity childToParent; } class JpaContext<T> { T parentEntity; @BeforeMapping void setEntity(@MappingTarget T parentEntity) { this.parentEntity = parentEntity; } @AfterMapping void establishRelation(@MappingTarget ParentRelation<T> childEntity) { childEntity.setChildToParent(parentEntity); } } interface BaseMapper<T, E> { default E toEntity(T s) { return toEntity(s, new JpaContext<>()); } E toEntity(T s, @Context JpaContext<E> ctx); } @Mapper interface SourceTargetMapper extends BaseMapper<ParentDto, ParentEntity> { }
In this case MapStruct does not invoke @BeforeMapping and @AfterMapping methods in SourceTargetMapperImpl, although it is allowed by Java assignment rules.
Generated Code
Desired generated code:
@Generated( value = "org.mapstruct.ap.MappingProcessor" ) class SourceTargetMapperImpl implements SourceTargetMapper { @Override public ParentEntity toEntity(ParentDto s, Ctx ctx) { if ( s == null ) { return null; } ParentEntity parentEntity = new ParentEntity(); ctx.setEntity( parentEntity ); parentEntity.setChild( childDtoToChildEntity( s.getChild(), ctx ) ); return parentEntity; } protected ChildEntity childDtoToChildEntity(ChildDto childDto, Ctx ctx) { if ( childDto == null ) { return null; } ChildEntity childEntity = new ChildEntity(); ctx.establishRelation( childEntity ); return childEntity; } }
Possible workarounds
Work around of this issue is to create derived class from JpaContext and use extra type parameter in the mapper to supply the derived class. The following example generates exactly the desired Generated Code above.
interface BaseMapper<T, E, C extends JpaContext<E>> { default E toEntity(T s) { return toEntity(s, getCtx()); } E toEntity(T s, @Context C ctx); C getCtx(); } @Mapper interface SourceTargetMapper extends BaseMapper<ParentDto, ParentEntity, SourceTargetMapper.Ctx> { default Ctx getCtx() { return new Ctx(); } class Ctx extends JpaContext<ParentEntity> { } }
MapStruct Version
1.6.0