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.api;
20  
21  import java.nio.file.Path;
22  import java.util.List;
23  import java.util.Optional;
24  
25  import org.apache.maven.api.annotations.Experimental;
26  import org.apache.maven.api.annotations.Nonnull;
27  import org.apache.maven.api.annotations.Nullable;
28  import org.apache.maven.api.model.Build;
29  import org.apache.maven.api.model.Model;
30  import org.apache.maven.api.model.Profile;
31  
32  /**
33   * Interface representing a Maven project which can be created using the
34   * {@link org.apache.maven.api.services.ProjectBuilder ProjectBuilder} service.
35   * Such objects are immutable and plugin that wish to modify such objects
36   * need to do so using the {@link org.apache.maven.api.services.ProjectManager
37   * ProjectManager} service.
38   * <p>
39   * Projects are created using the {@code ProjectBuilder} from a POM file
40   * (usually named {@code pom.xml}) on the file system.
41   * The {@link #getPomPath()} will point to the POM file and the
42   * {@link #getBasedir()} to the directory parent containing the
43   * POM file.
44   * </p>
45   *
46   * @since 4.0.0
47   * @see org.apache.maven.api.services.ProjectManager
48   * @see org.apache.maven.api.services.ProjectBuilder
49   */
50  @Experimental
51  public interface Project {
52  
53      /**
54       * {@return the project groupId}.
55       */
56      @Nonnull
57      String getGroupId();
58  
59      /**
60       * {@return the project artifactId}.
61       */
62      @Nonnull
63      String getArtifactId();
64  
65      /**
66       * {@return the project version}.
67       */
68      @Nonnull
69      String getVersion();
70  
71      /**
72       * {@return the project packaging}.
73       * <p>
74       * Note: unlike in legacy code, logical checks against string representing packaging (returned by this method)
75       * are NOT recommended (code like {@code "pom".equals(project.getPackaging)} must be avoided). Use method
76       * {@link #getArtifacts()} to gain access to POM or build artifact.
77       *
78       * @see #getArtifacts()
79       */
80      @Nonnull
81      Packaging getPackaging();
82  
83      /**
84       * {@return the project language}. It is by default determined by {@link #getPackaging()}.
85       *
86       * @see #getPackaging()
87       */
88      @Nonnull
89      default Language getLanguage() {
90          return getPackaging().language();
91      }
92  
93      /**
94       * {@return the project POM artifact}, which is the artifact of the POM of this project. Every project have a POM
95       * artifact, even if the existence of backing POM file is NOT a requirement (i.e. for some transient projects).
96       *
97       * @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact)
98       */
99      @Nonnull
100     default ProducedArtifact getPomArtifact() {
101         return getArtifacts().get(0);
102     }
103 
104     /**
105      * {@return the project main artifact}, which is the artifact produced by this project build, if applicable.
106      * This artifact MAY be absent if the project is actually not producing any main artifact (i.e. "pom" packaging).
107      *
108      * @see #getPackaging()
109      * @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact)
110      */
111     @Nonnull
112     default Optional<ProducedArtifact> getMainArtifact() {
113         List<ProducedArtifact> artifacts = getArtifacts();
114         return artifacts.size() == 2 ? Optional.of(artifacts.get(1)) : Optional.empty();
115     }
116 
117     /**
118      * {@return the project artifacts as immutable list}. Elements are the project POM artifact and the artifact
119      * produced by this project build, if applicable. Hence, the returned list may have one or two elements
120      * (never less than 1, never more than 2), depending on project packaging.
121      * <p>
122      * The list's first element is ALWAYS the project POM artifact. Presence of second element in the list depends
123      * solely on the project packaging.
124      *
125      * @see #getPackaging()
126      * @see #getPomArtifact()
127      * @see #getMainArtifact()
128      * @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact)
129      */
130     @Nonnull
131     List<ProducedArtifact> getArtifacts();
132 
133     /**
134      * {@return the project model}.
135      */
136     @Nonnull
137     Model getModel();
138 
139     /**
140      * Shorthand method.
141      *
142      * @return the build element of the project model
143      */
144     @Nonnull
145     default Build getBuild() {
146         Build build = getModel().getBuild();
147         return build != null ? build : Build.newInstance();
148     }
149 
150     /**
151      * Returns the path to the pom file for this project.
152      * A project is usually read from a file named {@code pom.xml},
153      * which contains the {@linkplain #getModel() model} in an XML form.
154      * When a custom {@code org.apache.maven.api.spi.ModelParser} is used,
155      * the path may point to a non XML file.
156      * <p>
157      * The POM path is also used to define the {@linkplain #getBasedir() base directory}
158      * of the project.
159      *
160      * @return the path of the pom
161      * @see #getBasedir()
162      */
163     @Nonnull
164     Path getPomPath();
165 
166     /**
167      * Returns the project base directory, i.e. the directory containing the project.
168      * A project is usually read from the file system and this will point to
169      * the directory containing the POM file.
170      *
171      * @return the path of the directory containing the project
172      */
173     @Nonnull
174     Path getBasedir();
175 
176     /**
177      * {@return the absolute path to the directory where files generated by the build are placed}
178      * <p>
179      * <strong>Purpose:</strong> This method provides the base output directory for a given scope,
180      * which serves as the destination for compiled classes, processed resources, and other generated files.
181      * The returned path is always absolute.
182      * </p>
183      * <p>
184      * <strong>Scope-based Directory Resolution:</strong>
185      * </p>
186      * <table class="striped">
187      *   <caption>Output Directory by Scope</caption>
188      *   <thead>
189      *     <tr>
190      *       <th>Scope Parameter</th>
191      *       <th>Build Configuration</th>
192      *       <th>Typical Path</th>
193      *       <th>Contents</th>
194      *     </tr>
195      *   </thead>
196      *   <tbody>
197      *     <tr>
198      *       <td>{@link ProjectScope#MAIN}</td>
199      *       <td>{@code build.getOutputDirectory()}</td>
200      *       <td>{@code target/classes}</td>
201      *       <td>Compiled application classes and processed main resources</td>
202      *     </tr>
203      *     <tr>
204      *       <td>{@link ProjectScope#TEST}</td>
205      *       <td>{@code build.getTestOutputDirectory()}</td>
206      *       <td>{@code target/test-classes}</td>
207      *       <td>Compiled test classes and processed test resources</td>
208      *     </tr>
209      *     <tr>
210      *       <td>{@code null} or other</td>
211      *       <td>{@code build.getDirectory()}</td>
212      *       <td>{@code target}</td>
213      *       <td>Parent directory for all build outputs</td>
214      *     </tr>
215      *   </tbody>
216      * </table>
217      * <p>
218      * <strong>Role in {@link SourceRoot} Path Resolution:</strong>
219      * </p>
220      * <p>
221      * This method is the foundation for {@link SourceRoot#targetPath(Project)} path resolution.
222      * When a {@link SourceRoot} has a relative {@code targetPath}, it is resolved against the
223      * output directory returned by this method for the source root's scope. This ensures that:
224      * </p>
225      * <ul>
226      *   <li>Main resources with {@code targetPath="META-INF"} are copied to {@code target/classes/META-INF}</li>
227      *   <li>Test resources with {@code targetPath="test-data"} are copied to {@code target/test-classes/test-data}</li>
228      *   <li>Resources without an explicit {@code targetPath} are copied to the root of the output directory</li>
229      * </ul>
230      * <p>
231      * <strong>Maven 3 Compatibility:</strong>
232      * </p>
233      * <p>
234      * This behavior maintains the Maven 3.x semantic where resource {@code targetPath} elements
235      * are resolved relative to the appropriate output directory ({@code project.build.outputDirectory}
236      * or {@code project.build.testOutputDirectory}), <strong>not</strong> the project base directory.
237      * </p>
238      * <p>
239      * In Maven 3, when a resource configuration specifies:
240      * </p>
241      * <pre>{@code
242      * <resource>
243      *   <directory>src/main/resources</directory>
244      *   <targetPath>META-INF/resources</targetPath>
245      * </resource>
246      * }</pre>
247      * <p>
248      * The maven-resources-plugin resolves {@code targetPath} as:
249      * {@code project.build.outputDirectory + "/" + targetPath}, which results in
250      * {@code target/classes/META-INF/resources}. This method provides the same base directory
251      * ({@code target/classes}) for Maven 4 API consumers.
252      * </p>
253      * <p>
254      * <strong>Example:</strong>
255      * </p>
256      * <pre>{@code
257      * Project project = ...; // project at /home/user/myproject
258      *
259      * // Get main output directory
260      * Path mainOutput = project.getOutputDirectory(ProjectScope.MAIN);
261      * // Result: /home/user/myproject/target/classes
262      *
263      * // Get test output directory
264      * Path testOutput = project.getOutputDirectory(ProjectScope.TEST);
265      * // Result: /home/user/myproject/target/test-classes
266      *
267      * // Get build directory
268      * Path buildDir = project.getOutputDirectory(null);
269      * // Result: /home/user/myproject/target
270      * }</pre>
271      *
272      * @param scope the scope of the generated files for which to get the directory, or {@code null} for the build directory
273      * @return the absolute path to the output directory for the given scope
274      *
275      * @see SourceRoot#targetPath(Project)
276      * @see SourceRoot#targetPath()
277      * @see Build#getOutputDirectory()
278      * @see Build#getTestOutputDirectory()
279      * @see Build#getDirectory()
280      */
281     @Nonnull
282     default Path getOutputDirectory(@Nullable ProjectScope scope) {
283         String dir;
284         Build build = getBuild();
285         if (scope == ProjectScope.MAIN) {
286             dir = build.getOutputDirectory();
287         } else if (scope == ProjectScope.TEST) {
288             dir = build.getTestOutputDirectory();
289         } else {
290             dir = build.getDirectory();
291         }
292         return getBasedir().resolve(dir);
293     }
294 
295     /**
296      * {@return the project direct dependencies (directly specified or inherited)}.
297      */
298     @Nonnull
299     List<DependencyCoordinates> getDependencies();
300 
301     /**
302      * {@return the project managed dependencies (directly specified or inherited)}.
303      */
304     @Nonnull
305     List<DependencyCoordinates> getManagedDependencies();
306 
307     /**
308      * {@return the project ID, usable as key}.
309      */
310     @Nonnull
311     default String getId() {
312         return getModel().getId();
313     }
314 
315     /**
316      * Returns a boolean indicating if the project is the top level project for
317      * this reactor build.  The top level project may be different from the
318      * {@code rootDirectory}, especially if a subtree of the project is being
319      * built, either because Maven has been launched in a subdirectory or using
320      * a {@code -f} option.
321      *
322      * @return {@code true} if the project is the top level project for this build
323      */
324     boolean isTopProject();
325 
326     /**
327      * Returns a boolean indicating if the project is a root project,
328      * meaning that the {@link #getRootDirectory()} and {@link #getBasedir()}
329      * points to the same directory, and that either {@link Model#isRoot()}
330      * is {@code true} or that {@code basedir} contains a {@code .mvn} child
331      * directory.
332      *
333      * @return {@code true} if the project is the root project
334      * @see Model#isRoot()
335      */
336     boolean isRootProject();
337 
338     /**
339      * Gets the root directory of the project, which is the parent directory
340      * containing the {@code .mvn} directory or flagged with {@code root="true"}.
341      *
342      * @return the root directory of the project
343      * @throws IllegalStateException if the root directory could not be found
344      * @see Session#getRootDirectory()
345      */
346     @Nonnull
347     Path getRootDirectory();
348 
349     /**
350      * Returns project parent project, if any.
351      * <p>
352      * Note that the model may have a parent defined, but an empty parent
353      * project may be returned if the parent comes from a remote repository,
354      * as a {@code Project} must refer to a buildable project.
355      *
356      * @return an optional containing the parent project
357      * @see Model#getParent()
358      */
359     @Nonnull
360     Optional<Project> getParent();
361 
362     /**
363      * Returns all profiles defined in this project.
364      * <p>
365      * This method returns only the profiles defined directly in the current project's POM
366      * and does not include profiles from parent projects.
367      *
368      * @return a non-null, possibly empty list of profiles defined in this project
369      * @see Profile
370      * @see #getEffectiveProfiles()
371      */
372     @Nonnull
373     List<Profile> getDeclaredProfiles();
374 
375     /**
376      * Returns all profiles defined in this project and all of its parent projects.
377      * <p>
378      * This method traverses the parent hierarchy and includes profiles defined in parent POMs.
379      * The returned list contains profiles from the current project and all of its ancestors in
380      * the project inheritance chain.
381      *
382      * @return a non-null, possibly empty list of all profiles from this project and its parents
383      * @see Profile
384      * @see #getDeclaredProfiles()
385      */
386     @Nonnull
387     List<Profile> getEffectiveProfiles();
388 
389     /**
390      * Returns all active profiles for the current project build.
391      * <p>
392      * Active profiles are those that have been explicitly activated through one of the following means:
393      * <ul>
394      *   <li>Command line activation using the -P flag</li>
395      *   <li>Maven settings activation in settings.xml via &lt;activeProfiles&gt;</li>
396      *   <li>Automatic activation via &lt;activation&gt; conditions</li>
397      *   <li>The default active profile (marked with &lt;activeByDefault&gt;true&lt;/activeByDefault&gt;)</li>
398      * </ul>
399      * <p>
400      * The active profiles control various aspects of the build configuration including but not
401      * limited to dependencies, plugins, properties, and build resources.
402      *
403      * @return a non-null, possibly empty list of active profiles for this project
404      * @see Profile
405      * @see #getEffectiveActiveProfiles()
406      */
407     @Nonnull
408     List<Profile> getDeclaredActiveProfiles();
409 
410     /**
411      * Returns all active profiles for this project and all of its parent projects.
412      * <p>
413      * This method traverses the parent hierarchy and collects all active profiles from
414      * the current project and its ancestors. Active profiles are those that meet the
415      * activation criteria through explicit activation or automatic conditions.
416      * <p>
417      * The combined set of active profiles from the entire project hierarchy affects
418      * the effective build configuration.
419      *
420      * @return a non-null, possibly empty list of all active profiles from this project and its parents
421      * @see Profile
422      * @see #getDeclaredActiveProfiles()
423      */
424     @Nonnull
425     List<Profile> getEffectiveActiveProfiles();
426 }