MapStruct - 基于 2 个或更多不同源对象的目标字段的自定义映射

MapStruct - custom mapping of target field based on 2 or more different source objects

我正在尝试弄清楚如何实现以下映射:

class SuperComplexClass {
    Long value;
    String description;
}

class MapIntoMe {
    
    // Many other fields that is also mapped
    
    SuperComplexClass superComplexObject;
}

class MapFromMe {
    ComplexClassPart1 complexClassPart;
}

class AdditionalData {
    ComplexClassPart2 complexClassPart;
}


@Mapper
public interface SomeFancyMapper {

    @Mapping(target = "superComplexObject", source = "{mfm.complexPart, ad.complexPart}",
             qualifiedByName = "mapSuperComplexObject")
    MapIntoMe mapFromMeIntoMe(MapFromMe mfm, AdditionalData ad);
    

    @Named("mapSuperComplexObject")
    default SuperComplexClass mapSuperComplexObject(ComplexPart1 p1, ComplexPart2 p2) {
        SuperComplexClass superObject = new SuperComplexClass();
        //some logic that calculates and fills superObject]
        return superObject;
    }
}

现在显然像 source = "{mfm.complexPart, ad.complexPart}" 这样的表达式不起作用,但它清楚地表明了我想要实现的目标。

到目前为止,如果没有一些丑陋的解决方法,我无法找到答案(如果可以的话)。

有什么想法吗?

目前不支持重复使用具有多个参数的映射方法。这就是为什么像您分享的表情这样的东西不起作用的原因。

但是,您可以使用 expression@AfterMapping@Context(如果您不需要对其他映射使用 AdditionalData)来实现您的目标需要。

使用表达式

@Mapper
public interface SomeFancyMapper {

    @Mapping(target = "superComplexObject", expression = "java(mapSuperComplexObject(mfm.getComplexPart(), ad.getComplexPart()))")
    MapIntoMe mapFromMeIntoMe(MapFromMe mfm, AdditionalData ad);
    

    default SuperComplexClass mapSuperComplexObject(ComplexPart1 p1, ComplexPart2 p2) {
        SuperComplexClass superObject = new SuperComplexClass();
        //some logic that calculates and fills superObject]
        return superObject;
    }
}

使用@AfterMapping

@Mapper
public interface SomeFancyMapper {

    @Mapping(target = "superComplexObject", ignore = true)
    MapIntoMe mapFromMeIntoMe(MapFromMe mfm, AdditionalData ad);
    
    @AfterMapping
    default void mapSuperComplexObject(@MappingTarget MapIntoMe target, MapFromMe mfm, AdditionalData ad) {

        SuperComplexClass superObject = new SuperComplexClass();
        //some logic that calculates and fills superObject]
        return superObject;
    }
}

使用@Context

@Mapper
public interface SomeFancyMapper {

    @Mapping(target = "superComplexObject", source = "complexPart",
             qualifiedByName = "mapSuperComplexObject")
    MapIntoMe mapFromMeIntoMe(MapFromMe mfm, @Context AdditionalData ad);
    

    @Named("mapSuperComplexObject")
    default SuperComplexClass mapSuperComplexObject(ComplexPart1 p1, @Context AdditionalData ad) {
        SuperComplexClass superObject = new SuperComplexClass();
        //some logic that calculates and fills superObject]
        return superObject;
    }
}

请记住,在使用 @Context 时,用该注释注释的参数不能在 Mapping#target 中使用。它是一个额外的上下文,可以传递给其他映射方法或生命周期方法。