Mapstruct - cannot find symbol [Kotlin + Maven]
Asked Answered
G

4

5

I'm having the following error when I run the command 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

It seems that after mapstruct has generated the DataMapperImpl.java class it is not able to find the classes DataMapper and DataMapperDecoretor.

The code related to mapstruct is in a xxx.kt file:

//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
    }
}

Regarding the pom files I have in the root file:

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

and this is the pom of the module where I'm using mapstruct:

...
        <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>
...

I hid some part of the files with dots and I'm not using the project Lombok (I saw same problems related with it we you are trying to use these projects together).

UPDATE 1:

I noticed that the error is related to the fact that from the generated class DataMapperImpl.java the package where there are the classes that this generated class should use is not visible. Indeed I see this error:

[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

and of course this package exist!

UPDATE 2:

I'm continuing to investigate on this issue. I tried to make it simpler deleting the DataMapperDecorator and put the DataMapper, the Data and the DataDto class in the same file. Still the same error cannot find symbol: class for all the three classes. I'm not sure if this is related to the fact that in the DataMapperImpl (the generated class) doesn't have the import of these classes. There are imports just for the standard java libraries such as:

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

EDIT 1:

From the log I can also see the following warning:

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

UPDATE 3:

Without mapstruct under target->classes (using IntelliJ IDEA) I can see the classes of my project. On the other hand when I have introduced mapstruct what I'm seeing is that the mapstruct classes are generated under target->generated-sources->kapt->compile but under target->classes I don't see the other classes. Could the mapstruct classes be generated earlier than the other classes of my project causing the compiler to not find the Data, DataDto classes?

Gherardo answered 17/8, 2021 at 15:0 Comment(0)
G
10

SOLVED!

The problem was due to the order of the compilation. By default the java compiler is executed before the kotlin compiler. That why the code generated by mapstruct wasn't able to find the kotlin classes. So it is needed to compiler the koltin classes before and then the java classes.

"The idea is to disable default compile execution and introduce our own to get control over the order in which goals are executed, so that we could run kotlin compiler before java compiler."

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

So the solution came introducing the maven plugin:

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

So I added this to my pom file:

             <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>
Gherardo answered 18/8, 2021 at 12:47 Comment(1)
This indeed worked, but also worked adding an execution step in kotlin-maven-plugin as Tom el Safadi suggested.Temper
C
1

Addition to @SGiux answer. The order of plugins in pom also matters:

  1. kotlin-maven-plugin
  2. maven-compiler-plugin
Cornerstone answered 30/3, 2022 at 1:32 Comment(0)
P
1

I just had to do the following change in kotlin-maven-plugin.

From:

<execution>
    <id>compile</id>
    <goals>
        <goal>compile</goal>
    </goals>
</execution>

To:

<execution>
    <id>compile</id>
    <phase>process-sources</phase>
    <goals>
        <goal>compile</goal>
    </goals>
</execution>
Purtenance answered 20/6, 2023 at 21:13 Comment(0)
D
0

I am not sure how Kotlin works with multiple classes in one source file.

What I would suggest is that you use dedicated files for the decorator and the mapper. That way MapStruct will create the correct code.

MapStruct is a Java annotation processor, we do not know anything about the Kotlin structure. It seems like the packages returned by the java annotation processing API are not correct.

Dispensary answered 17/8, 2021 at 17:20 Comment(1)
mmh I tried to put them in two different files but I have the same error for these classes. Actually I have the same error for Data and DataDto (the cannot find symbol error)Gherardo

© 2022 - 2024 — McMap. All rights reserved.