Mapstruct - 找不到符号 [Kotlin + Maven]

Mapstruct - cannot find symbol [Kotlin + Maven]

当我 运行 命令 mvn clean install:

时出现以下错误
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/target/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/DataMapperImpl.java:[10,40] cannot find symbol
[ERROR]   symbol: class DataMapperDecorator
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/target/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/DataMapperImpl.java:[10,74] cannot find symbol
[ERROR]   symbol: class DataMapper
[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/xxx/generated-sources/kapt/compile/com/xxx/xxx/xxx/api/DataMapperImpl.java:[12,19] cannot find symbol
[ERROR]   symbol:   class DataMapper
[ERROR]   location: class com.xxx.xxx.xxx.xxx.DataMapperImpl

似乎在 mapstruct 生成 DataMapperImpl.java class 之后,它无法找到 classes DataMapperDataMapperDecoretor

mapstruct相关代码在xxx.kt文件中:

//Other stuff
...

@Mapper
@DecoratedWith(DataMapperDecorator::class)
interface DataMapper {
    @Mappings(
        Mapping(source = "data.value", target = "dataValue"),
        Mapping(source = "data.current.value", target = "currentValue"),
    )
    fun toDto(data: Data) : RefDataDto
}

abstract class DataMapperDecorator : DataMapper {
    @Autowired
    private val delegate: DataMapper? = null

    override fun toDto(data: Data): dataDto {
        val dataDto = delegate!!.toDto(data)
        dataDto.primaryValue = data.primaryValue?.let { CurrencyUtil.toMajor(it) }
        return dataDto
    }
}

关于我在根文件中的 pom 个文件:

...
    <properties>
    ... 
        <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
    </properties>
...

这是我使用 mapstruct 的模块的 pom

...
        <build>
            <finalName>${project.artifactId}</finalName>
            <plugins>
                <plugin>
                    <groupId>org.jetbrains.kotlin</groupId>
                    <artifactId>kotlin-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>compile</id>
                            <phase>compile</phase>
                            <goals>
                                <goal>compile</goal>
                            </goals>
                            <configuration>
                                <sourceDirs>
                                    <sourceDir>src/main/kotlin</sourceDir>
                                </sourceDirs>
                            </configuration>
                        </execution>
                        <execution>
                            <id>test-compile</id>
                            <goals>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>kapt</id>
                            <goals>
                                <goal>kapt</goal>
                            </goals>
                            <configuration>
                                <annotationProcessorPaths>
                                    <annotationProcessorPath>
                                        <groupId>org.mapstruct</groupId>
                                        <artifactId>mapstruct-processor</artifactId>
                                        <version>${org.mapstruct.version}</version>
                                    </annotationProcessorPath>
                                </annotationProcessorPaths>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                ...
            </plugins>
...

我用点隐藏了部分文件并且我没有使用 Lombok 项目(我看到了与之相关的相同问题,我们正在尝试一起使用这些项目)。

更新 1:

我注意到该错误与以下事实有关:从生成的 class DataMapperImpl.java 包中,生成的 class 应该包含 classes使用是不可见的。确实我看到了这个错误:

[ERROR] /Users/xxx/xxx/xxx/xxx.xxx/xxx/generated-sources/kapt/compile/com/xxx/xxx/xxx/xxx/RefDataMapperImpl.java:[3,47] package com.my.package.application.domain does not exist

当然还有这个包!

更新 2:

我正在继续调查这个问题。我试图简化删除 DataMapperDecorator 并将 DataMapperDataDataDto class 放在同一个文件中。对于所有三个 classes,仍然是相同的错误 cannot find symbol: class。我不确定这是否与 DataMapperImpl(生成的 class)没有导入这些 classes 的事实有关。仅针对标准 java 库进行导入,例如:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import javax.annotation.processing.Generated;

编辑 1:

从日志中我还可以看到以下警告:

[WARNING] 'tools.jar' was not found, kapt may work unreliably

更新 3:

target->classes 下没有 mapstruct(使用 IntelliJ IDEA)我可以看到我项目的 classes。另一方面,当我介绍 mapstruct 时,我看到的是 mapstruct classes 是在 target->generated-sources->kapt->compile 下生成的,但在 target->classes 下我没有看到另一个 class ]是的。 mapstruct classes 是否会早于我项目的其他 classes 生成,导致编译器找不到 DataDataDto classes?

我不确定 Kotlin 如何在一个源文件中处理多个 类。

我建议您为装饰器和映射器使用专用文件。这样 MapStruct 将创建正确的代码。

MapStruct是一个Java注解处理器,我们对Kotlin结构一无所知。 java 注释处理 API 返回的包似乎不正确。

已解决!

问题出在编译顺序上。默认情况下,java 编译器在 kotlin 编译器之前执行。这就是为什么 mapstruct 生成的代码无法找到 kotlin 类 的原因。所以需要先编译koltin 类 然后再编译java 类.

"这个想法是禁用默认编译执行并引入我们自己的来控制目标执行的顺序,这样我们就可以 运行 kotlin 编译器在 [=31 之前=] 编译器。"

https://discuss.kotlinlang.org/t/maven-compiler-plugin-question/5260/4

所以引入maven插件解决方案来了:

https://kotlinlang.org/docs/maven.html#compile-kotlin-and-java-sources

所以我将其添加到我的 pom 文件中:

             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <executions>
                    <!-- Replacing default-compile as it is treated specially by maven -->
                    <execution>
                        <id>default-compile</id>
                        <phase>none</phase>
                    </execution>
                    <!-- Replacing default-testCompile as it is treated specially by maven -->
                    <execution>
                        <id>default-testCompile</id>
                        <phase>none</phase>
                    </execution>
                    <execution>
                        <id>java-compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>java-test-compile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

@SGiux 回答的补充。 pom 中插件的顺序也很重要:

  1. kotlin-maven-plugin
  2. maven-compiler-plugin