Skip to content

Output directories missing from javac --class-path in maven-compiler-plugin 4.0.0-beta-4 breaks mixed Kotlin+Java projects #1036

@shinkai-tester

Description

@shinkai-tester

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/classes is absent from javac's --class-path during compile
  • target/test-classes is absent from javac's --class-path during test-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.

repro-mixed-java-kotlin.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions