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

huangapple go评论60阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2020年10月3日 00:03:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/64174784.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定