为什么我不能在@Mapping 属性中引用@Context 参数?

Why can't I reference a @Context parameter in the @Mapping attributes?

使用 mapstruct,我需要的是一个具有多个源的映射方法,并且将这几个源传递给其他映射方法,这样我就可以在需要这些额外源的地方为所有映射方法提供所有几个源。

目前有两个功能可以协同工作:

因此,功能需要是允许将辅助源参数传递给其他映射方法,或者使 @Context 参数能够被 @Mapping(target="something", source="ctx.somethingElse")@Mapping(target="ctx.something", source="somethingElse)[ 引用=18=]

示例:

// source classes : `Instant timestamp` is a field I obtain separately

Instant timestamp;

class WrapperSource
   List<NestedSource> nested;

class NestedSource
    String name;



// target classes : I want to map the nested and name field but also to insert the timestamp in both the WrapperTarget and every NestedTarget in the nested list

class WrapperTarget
   Instant timestamp;
   List<NestedTarget> nested;

class NestedTarget
    String name;
    Instant timestamp;

理想情况下,映射类似于:

// Currently this doesn't work because we can't reference the @Context in the source attribute

@Mapping(target = "nested", source="source.nested")
@Mapping(target = "timestamp", source="timestamp")
WrapperTarget map(WrapperSource source, @Context Instant timestamp);

@Mapping(target = "name", source="source.name")
@Mapping(target = "timestamp", source="timestamp")
NestedTarget map(NestedSource source, @Context Instant timestamp);

或:

// Currently this doesn't work because the second method with 2 sources in not called by the first generated method

@Mapping(target = "nested", source="source.nested")
@Mapping(target = "timestamp", source="timestamp")
WrapperTarget map(WrapperSource source, Instant timestamp);

@Mapping(target = "name", source="source.name")
@Mapping(target = "timestamp", source="timestamp")
NestedTarget map(NestedSource source, Instant timestamp);

对我有用的唯一(详细)解决方法是:

// @Context is passed around and I can manually use it as a source in an @AfterMapping but it requires additional code

WrapperTarget map(WrapperSource source, @Context Instant timestamp);

@AfterMapping
void map(WrapperSource source, @MappingTarget WrapperTarget target, @Context Instant timestamp) {
    target.setTimestamp(timestamp);
}

NestedTarget map(NestedSource source, @Context Instant timestamp);

@AfterMapping
void map(NestedSource source, @MappingTarget NestedTarget target, @Context Instant timestamp) {
    target.setTimestamp(timestamp);
}

这工作正常,但它需要额外的手动代码,因此更好的选择是能够在 @Mapping's attributes 中引用 @Context。这样我就可以使用第一个“理想”映射示例。

这个问题有更好的解决方法吗?

@Context应该是什么参数提示什么。映射的上下文信息,因此不参与映射本身。映射原则上是从源到目标。

记住:MapStruct 可以解决很多问题,但它永远无法解决所有问题。

但是:你可以试试这个:

class WrapperTarget implements TimeStamped
   Instant timestamp;
   List<NestedTarget> nested;

class NestedTarget implements TimeStamped
    String name;
    Instance timestamp;

interface TimeStamped{
   void setTimestamp(Instance timeStamp);
}

定义您自己的上下文...MapStruct 在您自动定义的上下文上调用后映射。你可以像这样在上下文中放置更多的东西,例如在映射之前从存储库中解析内容,id 等

class MyContext {

    Instance timestamp;

    @AfterMapping
    map(@MappingTarget TimeStamped timeStamped)
}

在那种情况下,您的映射从上下文中保持清晰。在调用该方法之前,您当然需要初始化上下文。或许你可以在上下文的构造中构造时间点(如果要求你在所有地方都包含相同的时间点)..

@Mapping(target = "nested", source="source.nested")
WrapperTarget map(WrapperSource source, @Context MyContext ctx);

@Mapping(target = "name", source="source.name")
NestedTarget map(NestedSource source, @Context MyContext ctx);

对于上下文的使用,您可以查看this示例。