【问题标题】:How to create or enhance a custom annotation that uses mapstruct如何创建或增强使用 mapstruct 的自定义注释
【发布时间】:2020-05-23 18:56:20
【问题描述】:

Mapsturct 具有带有预定义属性的 @Mapping 注解 例如:@Mapping(source="", target="", qualifiedByName=""),如果我想添加另一个属性并使用它来计算逻辑怎么办

例如:@Mapping(source="", target="", qualifiedByName="" , version="")

我想将版本号传递给它,根据版本,它会从源设置目标。

我尝试创建自定义注释并在其中使用@Mapping,但没有帮助

@CustomMapping(version = "1.0", mapping = @Mapping(source = "", target = "", qualifiedByName=""))

【问题讨论】:

  • 您能否提供一些映射代码的示例?根据版本,我不明白您的意思?
  • 这将是我们从源映射到目标@Mapping(source = "numberOfSeats", target = "seatCount") CarDto carToCarDto(Car car) 的法线映射。在这个 @Mapping 注释中,我想添加一个版本字段,我们可以告诉我们这个映射是支持版本 1 还是版本 2,例如:@Mapping(source = "numberOfSeats", target = "seatCount", version=2) 表示仅当版本为 2 而不是版本 = 1 时才映射此字段
  • 我也在考虑创建另一个带有版本和映射属性的自定义注解,如果版本为 2,这个注解处理器将委托给 mapstruct 映射,但不知道如何做或实现这个..跨度>
  • 怎么知道是版本1还是2?
  • 让我们说它的定义像这样@Mapping(source = "numberOfSeats", target = "seatCount", version=2),这个版本值将来自属性或请求,如果版本是 2 做这个映射,我可以使用qualifiedByName 或表达式来做,但希望扩展此映射注释或创建自定义注释如@CustomMapping(version = "1.0", mapping = @Mapping(source = "", target = "", qualifiedByName="")) 来实现此目的。获得一些关于如何实现这一点的想法真的很有帮助

标签: java java-8 annotations mapstruct


【解决方案1】:

您为什么不直接定义第二个不同的注释以与@Mapping 一起使用?

@Mapping(source="", target="", qualifiedByName="")
@MappingVersion("1.0")
CarDto carToCarDto(Car car);

如果您担心在使用 @Mapping 时想要某种强制执行该版本始终存在,那么您可以很简单地使用 write an annotation processor,它在编译时执行此操作。

【讨论】:

  • 感谢您的想法,如果需要添加映射版本,那么我必须编写一个注释处理器,该处理器将在调用 mapstruct 的映射之前执行逻辑
【解决方案2】:

根据问题中的 cmets,我对需要做的事情有了更多的了解。基本上根据一些输入参数需要创建不同的映射方法。

不确定您的逻辑有多复杂。但是,您可以做的是创建自己的注释处理器,以便能够创建 MapStruct 映射器。

假设你有

@CustomMapper
public interface MyMapper {
    @CustomMapping(version = "1.0", mappings = { 
        @Mapping(source = "numberOfSeats", target = "seatCount", qualifiedByName="")
    })
    @CustomMapping(version = "2.0", mappings = { 
        @Mapping(source = "numberOfSeats", target = "seats", qualifiedByName="")
    })
    CarDto map(Car car, String version);
}

所以你的注释处理器需要处理CustomMapper。

处理器还会生成不同的 MapStruct 版本接口。

所以:

@Mapper
public interface MyMapperV1 {

    @Mapping(source = "numberOfSeats", target = "seatCount", qualifiedByName="")
    CarDto map(Car car)
}

@Mapper
public interface MyMapperV2 {

    @Mapping(source = "numberOfSeats", target = "seats", qualifiedByName="")
    CarDto map(Car car)
}

另外还有一个MyMapper 的实现。看起来像:

public class MyMapperImpl {

    protected MyMapperV1 myMapperV1 = Mappers.getMapper(MyMapperV1.class):
    protected MyMapperV2 myMapperV2 = Mappers.getMapper(MyMapperV2.class):

    public CarDto map(Car car, String version) {
        if ("1.0".equals(version)) {
            return myMapperV1.map(car);
        } else {
            return myMapperV2.map(car);
        }
    }
}

基本上,目标是让您的处理器生成 MapStruct 在同一编译轮次中获取的接口。这可以通过注释处理实现。

另一种选择是自己编写 MapStruct 映射器,并在调用者位置选择适合该版本的映射器。这实际上可能更简单。

【讨论】:

  • 非常感谢 Filip 提供我想要的东西,但不确定如何实现它,我将编写一个注释处理器来创建不同的 MapStruct 版本化接口。第二个选项如何编写 mapstruct 映射器?
  • 那么第二个选项是您自己手动编写MyMapperV1 和MyMapperV2,就像任何其他 MapStruct 映射器一样,然后当您需要调用它时,您会调用适当的映射器
  • 第一个选项会非常困难,因为在我当前的界面中我已经用@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE, uses={Class1.class, class2.class} 对其进行了注释。还有很多映射方法,如@Mapping(source = "numberOfSeats", target = "seats", qualifiedByName="formatSeatsValue")。因此,如果我编写自定义注释处理器,那么我必须生成 MyMapperV1,其中包含所有困难的映射,并且使用 @CustomMapper 注释代替 @mapper 注释会很麻烦
  • 哦,目前我有很多映射器,每个映射器都有很多方法,所以创建多个 v1、v2 的映射器将很难维护,任何支持版本的方法都会非常有帮助我正在尝试使用它来支持 api 版本控制,其中一些客户端将支持 10 个字段,而另一些则需要 20 个字段。如果能够为每个映射添加版本将非常好并且易​​于理解和维护,有什么方法可以扩展映射处理器以将版本属性挂钩到它
猜你喜欢
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多