mapstruct @SubclassMapping 注解可以与子类的 @Mapping 结合使用吗?

问题描述 投票:0回答:1

使用mapstruct v.1.5.5,java v.22。

假设我有一些实体想要映射到 DTO。 DTO 是 java 记录。

我的基本实体看起来像这样(简化):

public abstract class DateRule implements Predicate<LocalDate>
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected Long id;

}

假设我有 DateRule 的两个子类:AnnuaDateRule 和 DayOfWeekRule。 然后我有两个 java 记录:AnnualDateRuleDTO 和 DayOfWeekRuleDTO。 记录定义如下:

public record AnnualDateRuleDTO(Long id, String name, @NotNull Month targetMonth, @NotNull DayOfWeek targetDayOfWeek, @NotNull int nthOccurrence) implements DateRuleDTO {}


public record DayOfWeekRuleDTO(Long id, String name, @NotNull DayOfWeek dayToMatch) implements DateRuleDTO {}

我的映射器类定义如下:

@Mapper(componentModel = "spring", subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION)
public interface DateRuleDTOMapper
{
    @SubclassMapping(source = AnnualDateRule.class, target = AnnualDateRuleDTO.class)
    @SubclassMapping(source = DayOfWeekRule.class, target = DayOfWeekRuleDTO.class)
    DateRuleDTO dateRuleToDTO(DateRule rule);

    @SubclassMapping(source = AnnualDateRuleDTO.class, target = AnnualDateRule.class)
    @SubclassMapping(source = DayOfWeekRuleDTO.class, target = DayOfWeekRule.class)
    DateRule dateRuleFromDTO(DateRuleDTO dto);
}

根据@SubclassMapping注解的javadocs,“该注解可以与@Mapping注解结合使用。” 但是,我没有看到任何有关如何执行此操作的文档。

在编译时,我收到 id 字段未映射的警告

DateRuleDTOMapper.java:18: warning: Unmapped target property: "id". Mapping from SubclassMapping for us.lawyertools.datecalculator.core.AnnualDateRule "AnnualDateRule annualDateRule" to "AnnualDateRuleDTO annualDateRuleDTO". DateRuleDTO dateRuleToDTO(DateRule rule);
对于其他类,我也收到类似的警告。

因此,即使 AnnualDateRule 从其父 DateRule 继承“id”字段,mapstruct 也不会将其映射到 AnnualDateRuleDTO 上的目标“id”属性。

在运行时,正如您所期望的,给出警告,映射器返回 id 为 null 的 DTO 记录。

我尝试使用 @Mapping 注释上述 dateRuleToDTO 方法会导致编译器错误。 使用@Mapping注释,映射器如下所示:

@Mapper(componentModel = "spring", subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION)
public interface DateRuleDTOMapper
{
    @SubclassMapping(source = AnnualDateRule.class, target = AnnualDateRuleDTO.class)
    @SubclassMapping(source = DayOfWeekRule.class, target = DayOfWeekRuleDTO.class)
    @Mapping(source="id", target="id")
    DateRuleDTO dateRuleToDTO(DateRule rule);

    @SubclassMapping(source = AnnualDateRuleDTO.class, target = AnnualDateRule.class)
    @SubclassMapping(source = DayOfWeekRuleDTO.class, target = DayOfWeekRule.class)
    DateRule dateRuleFromDTO(DateRuleDTO dto);
}

编译错误:

DateRuleDTOMapper.java:18: error: No property named "id" exists in source parameter(s). Did you mean "name"? @Mapping(source="id", target="id") ^

如果我将 DateRule 的 id 字段更改为公共,编译器接下来会出错:

DateRuleDTOMapper.java:18: error: Unknown property "id" in result type DateRuleDTO. Did you mean "null"? @Mapping(source="id", target="id") ^

我正在尝试找到一种解决方案,不需要我为实现 DateRuleDTO 接口的每条记录编写自定义映射器,因为这首先会破坏使用 Mapstruct 注释的目的。 我找到了一种方法来或多或少地使用具有(恕我直言)丑陋反射的装饰器来完成此任务。 我想看看是否可以通过注释或最少的额外自定义获得我正在寻找的结果(自动映射每个记录的 id 字段)。

我还应该提到,我也在使用 lombok,并且在我的 gradle 构建文件中包含了 lombok-mapstruct-binding 依赖项:

    implementation "org.mapstruct:mapstruct:1.5.5.Final"
    annotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final"
    // https://mvnrepository.com/artifact/org.projectlombok/lombok-mapstruct-binding
    implementation group: 'org.projectlombok', name: 'lombok-mapstruct-binding', version: '0.2.0'
    annotationProcessor(group: 'org.projectlombok', name: 'lombok-mapstruct-binding', version: '0.2.0')
    // If you are using mapstruct in test code
    testAnnotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final"

感谢您的帮助!

java subclass mapstruct
1个回答
0
投票

您看到错误的原因是,当使用

DateRuleDto
作为源并且 MapStruct 尝试获取其属性来映射
else
SubclassMapping
分支时,它将找不到任何属性。

找不到属性的原因是属性在界面中使用类似记录的样式。

在任何情况下,MapStruct 甚至不应该尝试进行该映射,因为无法映射目标并且

subclassExhaustiveStrategy
SubclassExhaustiveStrategy.RUNTIME_EXCEPTION
。我建议尝试使用 1.6.0,因为该区域修复了一些错误

© www.soinside.com 2019 - 2024. All rights reserved.