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

pat*_*s91 1 java mapstruct

我试图弄清楚如何实现以下映射:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

到目前为止,我无法找到答案是否可以通过这种方法并且没有一些丑陋的解决方法。

有任何想法吗?

Fil*_*lip 5

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

但是,您可以使用expression, @AfterMappingor @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;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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