View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.compiler;
20  
21  import javax.lang.model.SourceVersion;
22  
23  import java.nio.file.Path;
24  import java.util.Locale;
25  
26  /**
27   * The way that source files are organized in a file system directory hierarchy.
28   * <a href="https://docs.oracle.com/en/java/javase/25/docs/specs/man/javac.html#directory-hierarchies">Directory
29   * hierarchies</a> are <i>package hierarchy</i>, <i>module hierarchy</i> and <i>module source hierarchy</i>, but
30   * for the purpose of the Maven Compiler Plugin we do not distinguish between the two latter.
31   *
32   * @see <a href="https://docs.oracle.com/en/java/javase/25/docs/specs/man/javac.html#directory-hierarchies">Directory hierarchies</a>
33   */
34  public enum DirectoryHierarchy {
35      /**
36       * Project using package hierarchy. This is the hierarchy used by all Java projects before Java 9.
37       * Note that it does not necessarily implies a class-path project. A modular project can still use
38       * the package hierarchy if the project contains only one module.
39       */
40      PACKAGE("versions"),
41  
42      /**
43       * Project using package hierarchy, but in which a {@code module-info} file has been detected.
44       * This is used for compilation of tests. For the main code, we pretend that the hierarchy is
45       * {@link #MODULE_SOURCE} and move the directory output after compilation. Therefore, this
46       * enumeration value can be understood as "pseudo module source hierarchy".
47       *
48       * @see ModuleDirectoryRemover
49       *
50       * @deprecated Used only for compatibility with Maven 3.
51       */
52      @Deprecated
53      PACKAGE_WITH_MODULE("versions"),
54  
55      /**
56       * A multi-module project using module source hierarchy. It could also be a module hierarchy,
57       * as the Maven Compiler Plugin does not need to distinguish <i>module hierarchy</i> and
58       * <i>module source hierarchy</i>.
59       */
60      MODULE_SOURCE("versions-modular");
61  
62      /**
63       * The {@value} directory.
64       */
65      static final String META_INF = "META-INF";
66  
67      /**
68       * Name of the {@code META-INF/} sub-directory where multi-release outputs are stored.
69       */
70      private final String versionDirectory;
71  
72      /**
73       * Creates a new enumeration value.
74       *
75       * @param versionDirectory name of the {@code META-INF/} sub-directory where multi-release outputs are stored
76       */
77      DirectoryHierarchy(String versionDirectory) {
78          this.versionDirectory = versionDirectory;
79      }
80  
81      /**
82       * Returns the directory where to write the compiled class files for all Java releases.
83       * The standard path for {@link #PACKAGE} hierarchy is {@code META-INF/versions}.
84       * The caller shall add the version number to the returned path.
85       *
86       * @param outputDirectory usually the value of {@link SourceDirectory#outputDirectory}
87       * @return the directory for all versions
88       */
89      public Path outputDirectoryForReleases(Path outputDirectory) {
90          // TODO: use Path.resolve(String, String...) with Java 22.
91          return outputDirectory.resolve(META_INF).resolve(versionDirectory);
92      }
93  
94      /**
95       * Returns the directory where to write the compiled class files for a specific Java release.
96       * The standard path is {@code META-INF/versions/${release}} where {@code ${release}} is the
97       * numerical value of the {@code release} argument. However for {@link #MODULE_SOURCE} case,
98       * the returned path is rather {@code META-INF/versions-modular/${release}}.
99       * The latter is non-standard because there is no standard multi-module <abbr>JAR</abbr> formats as of 2025.
100      * The use of {@code "versions-modular"} is for allowing other plugins such as Maven <abbr>JAR</abbr> plugin
101      * to avoid confusion with the standard case.
102      *
103      * @param outputDirectory usually the value of {@link SourceDirectory#outputDirectory}
104      * @param release the release, or {@code null} for the default release
105      * @return the directory for the classes of the specified version
106      */
107     public Path outputDirectoryForReleases(Path outputDirectory, SourceVersion release) {
108         if (release == null) {
109             release = SourceVersion.latestSupported();
110         }
111         String version = release.name(); // TODO: replace by runtimeVersion() in Java 18.
112         version = version.substring(version.lastIndexOf('_') + 1);
113         return outputDirectoryForReleases(outputDirectory).resolve(version);
114     }
115 
116     /**
117      * Returns a string representation for use in error message.
118      *
119      * @return human-readable string representation
120      */
121     @Override
122     public String toString() {
123         return name().replace('_', ' ').toLowerCase(Locale.US);
124     }
125 }