-
Notifications
You must be signed in to change notification settings - Fork 182
Description
Affected version
4.0.0-beta-4
Bug description
Environment
| Component | Version |
|---|---|
| Maven | 4.0.0-rc-5 |
| maven-compiler-plugin | 4.0.0-beta-4 |
| JDK | 21 |
| kotlin-maven-plugin | 2.3.20-RC |
| OS | Windows 11 |
A minimal reproducer project is attached.
Description
In a mixed Kotlin+Java project, kotlin-maven-plugin runs first during the compile phase
and writes .class files to target/classes. maven-compiler-plugin then invokes javac in
the same phase to compile Java sources that reference those Kotlin classes. This requires
target/classes to be on javac's --class-path.
The same applies to the test-compile phase: kotlinc test-compile writes .class files to
target/test-classes, after which javac needs target/test-classes on its --class-path.
With maven-compiler-plugin 3.15.0 both phases worked correctly.
With maven-compiler-plugin 4.0.0-beta-4 both are broken:
target/classesis absent from javac's--class-pathduringcompiletarget/test-classesis absent from javac's--class-pathduringtest-compile
Project structure (attached reproducer)
src/
main/
kotlin/org/example/Greeter.kt ← compiled by kotlinc → target/classes
java/org/example/Main.java ← uses Greeter, compiled by javac
test/
kotlin/org/example/GreeterTestHelper.kt ← compiled by kotlinc → target/test-classes
kotlin/org/example/GreeterKotlinTest.kt
java/org/example/GreeterJavaTest.java ← uses Greeter + GreeterTestHelper, compiled by javac
Steps to reproduce
Run in attached project:
./mvnw package
Expected behavior
javac can see .class files produced by earlier compilers that ran in the same phase, because
the output directory is on the --class-path.
Actual behavior
compile phase — target/classes missing
Main.java fails because Greeter.class (written by kotlinc moments earlier) is not on
javac's --class-path:
[INFO] --- compiler:4.0.0-beta-4:compile (default-compile) @ repro-mixed-java-kotlin ---
[INFO] Compiling all files.
[ERROR] cannot find symbol
symbol: class Greeter
location: class org.example.Main
at src\main\java\org\example\Main.java[5,32]
[INFO] Summary of compiler messages:
1 compiler.err.cant.resolve.location
Total:
1 error
[ERROR] COMPILATION ERROR: Cannot compile org.example:repro-mixed-java-kotlin:jar:1.0-SNAPSHOT main classes.
[INFO] For trying to compile from the command-line, use:
javac @target\javac.args
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] Total time: 5.619 s
[INFO] Finished at: 2026-02-25T23:19:14+01:00
[INFO] --------------------------------------------------------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:4.0.0-beta-4:compile (default-compile) on project repro-mixed-java-kotlin: Cannot compile org.example:repro-mixed-java-kotlin:jar:1.0-SNAPSHOT main classes.
[ERROR] The first error is: cannot find symbol
[ERROR] symbol: class Greeter
[ERROR] location: class org.example.Main
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the '-e' switch
[ERROR] Re-run Maven using the '-X' switch to enable verbose output
The plugin writes javac's arguments to target/javac.args. It confirms the problem directly:
--source 21
--target 21
--module-version 1.0-SNAPSHOT
--class-path "C:\Users\alexa\.m2\repository\org\jetbrains\kotlin\kotlin-stdlib\2.3.20-RC\kotlin-stdlib-2.3.20-RC.jar;C:\Users\alexa\.m2\repository\org\jetbrains\annotations\13.0\annotations-13.0.jar"
--source-path "src\main\java"
-d "target\classes"
"src\main\java\org\example\Main.java"
target/classes appears only as -d (output destination) but never on --class-path.
test-compile phase — target/test-classes missing
GreeterJavaTest.java fails because GreeterTestHelper.class (written by kotlinc test-compile
moments earlier) is not on javac's --class-path:
[INFO] --- compiler:4.0.0-beta-4:testCompile (default-testCompile) @ repro-mixed-java-kotlin ---
[INFO] Recompiling all files because all source files changed.
[ERROR] package GreeterTestHelper does not exist
at src\test\java\org\example\GreeterJavaTest.java[16,65]
[INFO] Summary of compiler messages:
1 compiler.err.doesnt.exist
Total:
1 error
[ERROR] COMPILATION ERROR: Cannot compile org.example:repro-mixed-java-kotlin:jar:1.0-SNAPSHOT test classes.
[INFO] For trying to compile from the command-line, use:
javac @C:\Users\alexa\IdeaProjects\Maven4_testing\repro-mixed-java-kotlin\target\javac-test.args
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] Total time: 5.897 s
[INFO] Finished at: 2026-02-25T23:21:53+01:00
[INFO] --------------------------------------------------------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:4.0.0-beta-4:testCompile (default-testCompile) on project repro-mixed-java-kotlin: Cannot compile org.example:repro-mixed-java-kotlin:jar:1.0-SNAPSHOT test classes.
[ERROR] The first error is: package GreeterTestHelper does not exist
target/javac-test.args confirms this. The plugin's --class-path does include
target/classes (as a normal test dependency) but not target/test-classes:
--class-path "C:\Users\alexa\IdeaProjects\Maven4_testing\repro-mixed-java-kotlin\target\classes;C:\Users\alexa\.m2\repository\org\junit\jupiter\junit-jupiter\6.0.3\junit-jupiter-6.0.3.jar;C:\Users\alexa\.m2\repository\org\jetbrains\kotlin\kotlin-stdlib\2.3.20-RC\kotlin-stdlib-2.3.20-RC.jar;C:\Users\alexa\.m2\repository\org\junit\jupiter\junit-jupiter-api\6.0.3\junit-jupiter-api-6.0.3.jar;C:\Users\alexa\.m2\repository\org\junit\jupiter\junit-jupiter-params\6.0.3\junit-jupiter-params-6.0.3.jar;C:\Users\alexa\.m2\repository\org\jetbrains\annotations\13.0\annotations-13.0.jar;C:\Users\alexa\.m2\repository\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;C:\Users\alexa\.m2\repository\org\junit\platform\junit-platform-commons\6.0.3\junit-platform-commons-6.0.3.jar;C:\Users\alexa\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;C:\Users\alexa\.m2\repository\org\jspecify\jspecify\1.0.0\jspecify-1.0.0.jar"
--source-path "C:\Users\alexa\IdeaProjects\Maven4_testing\repro-mixed-java-kotlin\src\test\java"
-d "C:\Users\alexa\IdeaProjects\Maven4_testing\repro-mixed-java-kotlin\target\test-classes"
"C:\Users\alexa\IdeaProjects\Maven4_testing\repro-mixed-java-kotlin\src\test\java\org\example\GreeterJavaTest.java"
Workaround
Just to use maven-compiler plugin of version 3.15.0.
OR
Use maven-dependency-plugin:build-classpath to materialize the dependency classpath as a
path-separated string, then prepend the output directories via <compilerArgs> /
<testCompilerArgs>. Two separate properties are needed because test-scope JARs (e.g.
junit-jupiter) must be included for testCompile but not for compile:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>build-classpath</id>
<phase>initialize</phase>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputProperty>dep.classpath</outputProperty>
<includeScope>compile</includeScope>
<includeScope>test</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>--class-path</arg>
<arg>
${project.build.testOutputDirectory}${path.separator}${project.build.outputDirectory}${path.separator}${dep.classpath}
</arg>
</compilerArgs>
<testCompilerArgs>
<arg>--class-path</arg>
<arg>
${project.build.testOutputDirectory}${path.separator}${project.build.outputDirectory}${path.separator}${dep.classpath}
</arg>
</testCompilerArgs>
</configuration>
</plugin>The dep.classpath / test.dep.classpath properties are set at initialize phase and are
therefore unavailable at POM parse time (IDEs may highlight them red; this is a false alarm).
The attached project's pom.xml contains the full working workaround.
This workaround is non-trivial and fragile.