diff --git a/src/it/multirelease-with-modules/verify.groovy b/src/it/multirelease-with-modules/verify.groovy index a4d068ae5..146fa96ac 100644 --- a/src/it/multirelease-with-modules/verify.groovy +++ b/src/it/multirelease-with-modules/verify.groovy @@ -27,8 +27,8 @@ assert baseVersion == getMajor(new File( basedir, "target/classes/foo.bar/foo/Ot assert baseVersion == getMajor(new File( basedir, "target/classes/foo.bar/foo/YetAnotherFile.class")) assert baseVersion == getMajor(new File( basedir, "target/classes/foo.bar.more/more/MainFile.class")) assert baseVersion == getMajor(new File( basedir, "target/classes/foo.bar.more/more/OtherFile.class")) -assert nextVersion == getMajor(new File( basedir, "target/classes/META-INF/versions/16/foo.bar/foo/OtherFile.class")) -assert nextVersion == getMajor(new File( basedir, "target/classes/META-INF/versions/16/foo.bar.more/more/OtherFile.class")) +assert nextVersion == getMajor(new File( basedir, "target/classes/META-INF/versions-modular/16/foo.bar/foo/OtherFile.class")) +assert nextVersion == getMajor(new File( basedir, "target/classes/META-INF/versions-modular/16/foo.bar.more/more/OtherFile.class")) int getMajor(File file) { diff --git a/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java b/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java index a62e2ec80..373f07319 100644 --- a/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java +++ b/src/main/java/org/apache/maven/plugin/compiler/CompilerMojo.java @@ -267,7 +267,8 @@ protected Set getIncrementalExcludes() { @Override protected Path getOutputDirectory() { if (SUPPORT_LEGACY && multiReleaseOutput && release != null) { - return SourceDirectory.outputDirectoryForReleases(outputDirectory).resolve(release); + return SourceDirectory.outputDirectoryForReleases(false, outputDirectory) + .resolve(release); } return outputDirectory; } @@ -340,7 +341,7 @@ final boolean hasModuleDeclaration(final List roots) throws IOE */ @Deprecated(since = "4.0.0") private TreeMap getOutputDirectoryPerVersion() throws IOException { - final Path root = SourceDirectory.outputDirectoryForReleases(outputDirectory); + final Path root = SourceDirectory.outputDirectoryForReleases(false, outputDirectory); if (Files.notExists(root)) { return null; } @@ -365,7 +366,7 @@ private TreeMap getOutputDirectoryPerVersion() throws IOExc } /** - * Adds the compilation outputs of previous Java releases to the class-path ot module-path. + * Adds the compilation outputs of previous Java releases to the class-path of module-path. * This method should be invoked only when compiling a multi-release JAR in the * old deprecated way. * diff --git a/src/main/java/org/apache/maven/plugin/compiler/SourceDirectory.java b/src/main/java/org/apache/maven/plugin/compiler/SourceDirectory.java index 45f05058e..bb4ee92a0 100644 --- a/src/main/java/org/apache/maven/plugin/compiler/SourceDirectory.java +++ b/src/main/java/org/apache/maven/plugin/compiler/SourceDirectory.java @@ -140,9 +140,9 @@ final class SourceDirectory { * This is the MOJO output directory with sub-directories appended according the following rules, in that order: * *
    - *
  1. If {@link #moduleName} is non-null, then the module name is appended.
  2. - *
  3. If {@link #isVersioned} is {@code true}, then the next elements in the paths are + *
  4. If {@link #isVersioned} is {@code true}, then the relative part of the path starts with * {@code "META-INF/versions/"} where {@code } is the release number.
  5. + *
  6. If {@link #moduleName} is non-null, then the module name is appended.
  7. *
* * @see #getOutputDirectory() @@ -194,6 +194,8 @@ private SourceDirectory( * Potentially adds the {@code META-INF/versions/} part of the path to the output directory. * This method can be invoked only after the base version has been determined, which happens * after all other source directories have been built. + * + * @param baseVersion the Java release target by the non-versioned classes */ private void completeIfVersioned(SourceVersion baseVersion) { @SuppressWarnings("LocalVariableHidesMemberVariable") @@ -204,32 +206,45 @@ private void completeIfVersioned(SourceVersion baseVersion) { release = SourceVersion.latestSupported(); // `this.release` intentionally left to null. } - outputDirectory = outputDirectoryForReleases(outputDirectory, release); + outputDirectory = outputDirectoryForReleases(moduleName != null, outputDirectory, release); } } /** - * Returns the directory where to write the compilation for a specific Java release. + * Returns the directory where to write the compiled class files for a specific Java release. + * The standard path is {@code META-INF/versions/${release}} where {@code ${release}} is the + * numerical value of the {@code release} argument. However if {@code modular} is {@code true}, + * then the returned path is rather {@code META-INF/versions-modular/${release}}. The latter is + * non-standard because there is no standard multi-module JAR formats as of 2025. + * The use of {@code "versions-modular"} is for allowing other plugins such as Maven JAR plugin + * to avoid confusion with the standard case. * + * @param modular whether each version directory contains module names * @param outputDirectory usually the value of {@link #outputDirectory} * @param release the release, or {@code null} for the default release + * @return the directory for the classes of the specified version */ - static Path outputDirectoryForReleases(Path outputDirectory, SourceVersion release) { + static Path outputDirectoryForReleases(boolean modular, Path outputDirectory, SourceVersion release) { if (release == null) { release = SourceVersion.latestSupported(); } String version = release.name(); // TODO: replace by runtimeVersion() in Java 18. version = version.substring(version.lastIndexOf('_') + 1); - return outputDirectoryForReleases(outputDirectory).resolve(version); + return outputDirectoryForReleases(modular, outputDirectory).resolve(version); } /** - * Returns the directory where to write the compilation for a specific Java release. + * Returns the directory where to write the compiled class files for all Java releases. + * The standard path (when {@code modular} is {@code false}) is {@code META-INF/versions}. * The caller shall add the version number to the returned path. + * + * @param modular whether each version directory contains module names + * @param outputDirectory usually the value of {@link #outputDirectory} + * @return the directory for all versions */ - static Path outputDirectoryForReleases(Path outputDirectory) { + static Path outputDirectoryForReleases(boolean modular, Path outputDirectory) { // TODO: use Path.resolve(String, String...) with Java 22. - return outputDirectory.resolve("META-INF").resolve("versions"); + return outputDirectory.resolve("META-INF").resolve(modular ? "versions-modular" : "versions"); } /** diff --git a/src/main/java/org/apache/maven/plugin/compiler/ToolExecutor.java b/src/main/java/org/apache/maven/plugin/compiler/ToolExecutor.java index c32d7bfea..1a9b1f29c 100644 --- a/src/main/java/org/apache/maven/plugin/compiler/ToolExecutor.java +++ b/src/main/java/org/apache/maven/plugin/compiler/ToolExecutor.java @@ -614,8 +614,8 @@ public boolean compile(final JavaCompiler compiler, final Options configuration, } outputForRelease = outputDirectory; // Modified below if compiling a non-base release. if (isVersioned) { - outputForRelease = Files.createDirectories( - SourceDirectory.outputDirectoryForReleases(outputForRelease, unit.release)); + outputForRelease = Files.createDirectories(SourceDirectory.outputDirectoryForReleases( + isModularProject, outputForRelease, unit.release)); if (isClasspathProject) { /* * For a non-modular project, this block is executed at most once par compilation unit.