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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions