英文:
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}" 这样的表达式是不起作用的,但它清楚地显示了我想要实现的内容。
到目前为止,我无法找到答案,是否可以通过这种方法实现,而不需要一些丑陋的变通方法。
有什么想法吗?
英文:
I am trying to figure out how to implement the following mapping:
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;
    }
}
And now obviously expression like source = "{mfm.complexPart, ad.complexPart}" is not working, but it shows clearly what I would like to achieve.
So far I wasn't able to find the answer if that's possible with this approach and without some ugly workarounds.
Any ideas?
答案1
得分: 5
目前不支持重用带有多个参数的映射方法。这就是为什么类似于您分享的表达式不起作用的原因。
但是,您可以使用 expression、@AfterMapping 或者 @Context(如果您不需要在其他映射中使用 AdditionalData)来实现您需要的功能。
使用 Expression
@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
        target.setSuperComplexObject(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 中使用。它是一个附加的上下文,可以传递给其他映射方法或生命周期方法。
英文:
Currently it is not supported to reuse mapping methods with more than one parameter. That is why something like the expression you shared doesn't work.
However, you could use expression, @AfterMapping or @Context (in case you don't need to use AdditionalData for other mapping) to achieve what you need.
Using Expression
@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;
    }
}
Using @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;
    }
}
Using @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;
    }
}
Keep in mind that when using @Context the parameter annotated with that annotation cannot be used in Mapping#target. It is an additional context that can be passed to other mapping methods or lifecycle methods.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论