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.project;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.Writer;
24  import java.nio.file.Path;
25  import java.util.AbstractSequentialList;
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.LinkedHashMap;
31  import java.util.LinkedHashSet;
32  import java.util.List;
33  import java.util.ListIterator;
34  import java.util.Map;
35  import java.util.Objects;
36  import java.util.Properties;
37  import java.util.Set;
38  import java.util.function.Predicate;
39  import java.util.stream.Stream;
40  
41  import org.apache.maven.RepositoryUtils;
42  import org.apache.maven.api.Language;
43  import org.apache.maven.api.ProjectScope;
44  import org.apache.maven.api.SourceRoot;
45  import org.apache.maven.api.annotations.Nonnull;
46  import org.apache.maven.artifact.Artifact;
47  import org.apache.maven.artifact.ArtifactUtils;
48  import org.apache.maven.artifact.DependencyResolutionRequiredException;
49  import org.apache.maven.artifact.factory.ArtifactFactory;
50  import org.apache.maven.artifact.handler.ArtifactHandler;
51  import org.apache.maven.artifact.repository.ArtifactRepository;
52  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
53  import org.apache.maven.impl.DefaultSourceRoot;
54  import org.apache.maven.lifecycle.internal.DefaultProjectArtifactFactory;
55  import org.apache.maven.model.Build;
56  import org.apache.maven.model.CiManagement;
57  import org.apache.maven.model.Contributor;
58  import org.apache.maven.model.Dependency;
59  import org.apache.maven.model.DependencyManagement;
60  import org.apache.maven.model.Developer;
61  import org.apache.maven.model.DistributionManagement;
62  import org.apache.maven.model.Extension;
63  import org.apache.maven.model.IssueManagement;
64  import org.apache.maven.model.License;
65  import org.apache.maven.model.MailingList;
66  import org.apache.maven.model.Model;
67  import org.apache.maven.model.Organization;
68  import org.apache.maven.model.Plugin;
69  import org.apache.maven.model.PluginExecution;
70  import org.apache.maven.model.PluginManagement;
71  import org.apache.maven.model.Prerequisites;
72  import org.apache.maven.model.Profile;
73  import org.apache.maven.model.ReportPlugin;
74  import org.apache.maven.model.ReportSet;
75  import org.apache.maven.model.Reporting;
76  import org.apache.maven.model.Repository;
77  import org.apache.maven.model.Resource;
78  import org.apache.maven.model.Scm;
79  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
80  import org.apache.maven.model.root.RootLocator;
81  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
82  import org.codehaus.plexus.classworlds.realm.ClassRealm;
83  import org.codehaus.plexus.util.xml.Xpp3Dom;
84  import org.eclipse.aether.graph.DependencyFilter;
85  import org.eclipse.aether.repository.RemoteRepository;
86  import org.slf4j.Logger;
87  import org.slf4j.LoggerFactory;
88  
89  /**
90   * The concern of the project is provide runtime values based on the model.
91   * <p>
92   * The values in the model remain untouched but during the process of building a project notions like inheritance and
93   * interpolation can be added. This allows to have an entity which is useful in a runtime while preserving the model so
94   * that it can be marshalled and unmarshalled without being tainted by runtime requirements.
95   * </p>
96   * <p>
97   * With changes during 3.2.2 release MavenProject is closer to being immutable after construction with the removal of
98   * all components from this class, and the upfront construction taken care of entirely by the {@link ProjectBuilder}.
99   * There is still the issue of having to run the lifecycle in order to find all the compile source roots and resource
100  * directories but I hope to take care of this during the Maven 4.0 release (jvz).
101  * </p>
102  */
103 public class MavenProject implements Cloneable {
104 
105     private static final Logger LOGGER = LoggerFactory.getLogger(MavenProject.class);
106 
107     public static final String EMPTY_PROJECT_GROUP_ID = "unknown";
108 
109     public static final String EMPTY_PROJECT_ARTIFACT_ID = "empty-project";
110 
111     public static final String EMPTY_PROJECT_VERSION = "0";
112 
113     private Model model;
114 
115     private MavenProject parent;
116 
117     private File file;
118 
119     private File basedir;
120 
121     private Path rootDirectory;
122 
123     private Set<Artifact> resolvedArtifacts;
124 
125     private ArtifactFilter artifactFilter;
126 
127     private Set<Artifact> artifacts;
128 
129     private Artifact parentArtifact;
130 
131     private Set<Artifact> pluginArtifacts;
132 
133     @Deprecated
134     private List<ArtifactRepository> remoteArtifactRepositories;
135 
136     @Deprecated
137     private List<ArtifactRepository> pluginArtifactRepositories;
138 
139     private List<RemoteRepository> remoteProjectRepositories;
140 
141     private List<RemoteRepository> remotePluginRepositories;
142 
143     private List<Artifact> attachedArtifacts = new ArrayList<>();
144 
145     private MavenProject executionProject;
146 
147     private List<MavenProject> collectedProjects;
148 
149     /**
150      * All sources of this project, in the order they were added.
151      */
152     Set<SourceRoot> sources = new LinkedHashSet<>();
153 
154     @Deprecated
155     private ArtifactRepository releaseArtifactRepository;
156 
157     @Deprecated
158     private ArtifactRepository snapshotArtifactRepository;
159 
160     private List<Profile> activeProfiles = new ArrayList<>();
161 
162     private Map<String, List<String>> injectedProfileIds = new LinkedHashMap<>();
163 
164     @Deprecated
165     private Set<Artifact> dependencyArtifacts;
166 
167     private Artifact artifact;
168 
169     // calculated.
170     private Map<String, Artifact> artifactMap;
171 
172     private Model originalModel;
173 
174     private Map<String, Artifact> pluginArtifactMap;
175 
176     @Deprecated
177     private Set<Artifact> reportArtifacts;
178 
179     @Deprecated
180     private Map<String, Artifact> reportArtifactMap;
181 
182     @Deprecated
183     private Set<Artifact> extensionArtifacts;
184 
185     @Deprecated
186     private Map<String, Artifact> extensionArtifactMap;
187 
188     private Map<String, Artifact> managedVersionMap;
189 
190     private Map<String, MavenProject> projectReferences = new HashMap<>();
191 
192     private boolean executionRoot;
193 
194     private File parentFile;
195 
196     private Map<String, Object> context;
197 
198     private ClassRealm classRealm;
199 
200     private DependencyFilter extensionDependencyFilter;
201 
202     private final Set<String> lifecyclePhases = Collections.synchronizedSet(new LinkedHashSet<>());
203 
204     public MavenProject() {
205         Model model = new Model();
206 
207         model.setGroupId(EMPTY_PROJECT_GROUP_ID);
208         model.setArtifactId(EMPTY_PROJECT_ARTIFACT_ID);
209         model.setVersion(EMPTY_PROJECT_VERSION);
210 
211         setModel(model);
212     }
213 
214     public MavenProject(org.apache.maven.api.model.Model model) {
215         this(new Model(model));
216     }
217 
218     public MavenProject(Model model) {
219         setModel(model);
220     }
221 
222     public MavenProject(MavenProject project) {
223         deepCopy(project);
224     }
225 
226     public File getParentFile() {
227         return parentFile;
228     }
229 
230     public void setParentFile(File parentFile) {
231         this.parentFile = parentFile;
232     }
233 
234     // ----------------------------------------------------------------------
235     // Accessors
236     // ----------------------------------------------------------------------
237 
238     public Artifact getArtifact() {
239         return artifact;
240     }
241 
242     public void setArtifact(Artifact artifact) {
243         this.artifact = artifact;
244     }
245 
246     // TODO I would like to get rid of this. jvz.
247     public Model getModel() {
248         return model;
249     }
250 
251     /**
252      * Returns the project corresponding to a declared parent.
253      *
254      * @return the parent, or null if no parent is declared or there was an error building it
255      */
256     public MavenProject getParent() {
257         return parent;
258     }
259 
260     public void setParent(MavenProject parent) {
261         this.parent = parent;
262     }
263 
264     public boolean hasParent() {
265         return getParent() != null;
266     }
267 
268     public File getFile() {
269         return file;
270     }
271 
272     public void setFile(File file) {
273         this.file = file;
274         this.basedir = file != null ? file.getParentFile() : null;
275     }
276 
277     /**
278      * Sets project {@code file} without changing project {@code basedir}.
279      *
280      * @since 3.2.4
281      */
282     public void setPomFile(File file) {
283         this.file = file;
284     }
285 
286     /**
287      * @deprecated Replaced by {@link #getBaseDirectory()} for migrating from {@code File} to {@code Path}.
288      */
289     @Deprecated(since = "4.0.0")
290     public File getBasedir() {
291         return basedir;
292     }
293 
294     /**
295      * {@return the base directory of this project}.
296      * All source files are relative to this directory, unless they were specified as absolute paths.
297      *
298      * @since 4.0.0
299      */
300     public Path getBaseDirectory() {
301         return getBasedir().toPath();
302     }
303 
304     public void setDependencies(List<Dependency> dependencies) {
305         getModel().setDependencies(dependencies);
306     }
307 
308     public List<Dependency> getDependencies() {
309         return getModel().getDependencies();
310     }
311 
312     public DependencyManagement getDependencyManagement() {
313         return getModel().getDependencyManagement();
314     }
315 
316     // ----------------------------------------------------------------------
317     // Test and compile source roots.
318     // ----------------------------------------------------------------------
319 
320     /**
321      * Adds the given source if not already present.
322      *
323      * @param source the source to add
324      *
325      * @see #getSourceRoots()
326      *
327      * @since 4.0.0
328      */
329     public void addSourceRoot(SourceRoot source) {
330         sources.add(source);
331     }
332 
333     /**
334      * Resolves and adds the given directory as a source with the given scope and language.
335      * First, this method resolves the given root against the {@linkplain #getBaseDirectory() base directory},
336      * then normalizes the path. If a source already exists for the same scope, language and normalized directory,
337      * this method does nothing. Otherwise, the normalized directory is added as a new {@link SourceRoot} element.
338      *
339      * @param scope scope (main or test) of the directory to add
340      * @param language language of the files contained in the directory to add
341      * @param directory the directory to add if not already present in the source
342      *
343      * @see #getEnabledSourceRoots(ProjectScope, Language)
344      *
345      * @since 4.0.0
346      */
347     public void addSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull Path directory) {
348         directory = getBaseDirectory()
349                 .resolve(Objects.requireNonNull(directory, "directory cannot be null"))
350                 .normalize();
351         addSourceRoot(new DefaultSourceRoot(scope, language, directory));
352     }
353 
354     /**
355      * Resolves and adds the given directory as a source with the given scope and language.
356      * If the given directory is null, blank or already in the sources, then this method does nothing.
357      * Otherwise, the directory is converted to a path, resolved, normalized and finally added as a new
358      * {@link SourceRoot} element if no source exists for these scope, language and normalized directory.
359      *
360      * @param scope scope (main or test) of the directory to add
361      * @param language language of the files contained in the directory to add
362      * @param directory the directory to add if not already present in the source, or null
363      *
364      * @since 4.0.0
365      */
366     public void addSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull String directory) {
367         directory =
368                 Objects.requireNonNull(directory, "directory cannot be null").trim();
369         if (!directory.isBlank()) {
370             Path path = getBaseDirectory().resolve(directory).normalize();
371             addSourceRoot(scope, language, path);
372         }
373     }
374 
375     /**
376      * Removes a source root from the project.
377      *
378      * @param scope the scope of the source root
379      * @param language the language of the source root
380      * @param directory the directory of the source root
381      */
382     public void removeSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull Path directory) {
383         Path path = getBaseDirectory()
384                 .resolve(Objects.requireNonNull(directory, "directory cannot be null"))
385                 .normalize();
386         sources.removeIf(source -> source.scope() == scope
387                 && source.language() == language
388                 && source.directory().equals(path));
389     }
390 
391     /**
392      * Removes a source root from the project.
393      *
394      * @param scope the scope of the source root
395      * @param language the language of the source root
396      * @param directory the directory of the source root
397      */
398     public void removeSourceRoot(@Nonnull ProjectScope scope, @Nonnull Language language, @Nonnull String directory) {
399         directory =
400                 Objects.requireNonNull(directory, "directory cannot be null").trim();
401         if (!directory.isBlank()) {
402             removeSourceRoot(scope, language, Path.of(directory));
403         }
404     }
405 
406     /**
407      * @deprecated Replaced by {@code addSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path)}.
408      */
409     @Deprecated(since = "4.0.0")
410     public void addCompileSourceRoot(String path) {
411         addSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path);
412     }
413 
414     /**
415      * @deprecated Replaced by {@code removeSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path)}.
416      */
417     @Deprecated(since = "4.0.0")
418     public void removeCompileSourceRoot(String path) {
419         removeSourceRoot(ProjectScope.MAIN, Language.JAVA_FAMILY, path);
420     }
421 
422     /**
423      * @deprecated Replaced by {@code addSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path)}.
424      */
425     @Deprecated(since = "4.0.0")
426     public void addTestCompileSourceRoot(String path) {
427         addSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path);
428     }
429 
430     /**
431      * @deprecated Replaced by {@code removeSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path)}.
432      */
433     public void removeTestCompileSourceRoot(String path) {
434         removeSourceRoot(ProjectScope.TEST, Language.JAVA_FAMILY, path);
435     }
436     /**
437      * {@return all source root directories, including the disabled ones, for all languages and scopes}.
438      * The iteration order is the order in which the sources are declared in the POM file.
439      * The returned collection is unmodifiable.
440      *
441      * @see #addSourceRoot(SourceRoot)
442      */
443     public Collection<SourceRoot> getSourceRoots() {
444         return Collections.unmodifiableCollection(sources);
445     }
446 
447     /**
448      * {@return all enabled sources that provide files in the given language for the given scope}.
449      * If the given scope is {@code null}, then this method returns the enabled sources for all scopes.
450      * If the given language is {@code null}, then this method returns the enabled sources for all languages.
451      * The iteration order is the order in which the sources are declared in the POM file.
452      *
453      * @param scope the scope of the sources to return, or {@code null} for all scopes
454      * @param language the language of the sources to return, or {@code null} for all languages
455      *
456      * @see #addSourceRoot(ProjectScope, Language, Path)
457      *
458      * @since 4.0.0
459      */
460     public Stream<SourceRoot> getEnabledSourceRoots(ProjectScope scope, Language language) {
461         Stream<SourceRoot> stream = sources.stream().filter(SourceRoot::enabled);
462         if (scope != null) {
463             stream = stream.filter(source -> scope.equals(source.scope()));
464         }
465         if (language != null) {
466             stream = stream.filter(source -> language.equals(source.language()));
467         }
468         return stream;
469     }
470 
471     /**
472      * Returns a list of paths for the given scope.
473      *
474      * @deprecated Used only for the implementation of deprecated methods.
475      */
476     @Deprecated
477     private List<String> getSourceRootDirs(ProjectScope scope, Language language) {
478         return getEnabledSourceRoots(scope, language)
479                 .map((source) -> source.directory().toString())
480                 .toList();
481     }
482 
483     /**
484      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)}.
485      */
486     @Deprecated(since = "4.0.0")
487     public List<String> getCompileSourceRoots() {
488         return getSourceRootDirs(ProjectScope.MAIN, Language.JAVA_FAMILY);
489     }
490 
491     /**
492      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)}.
493      */
494     @Deprecated(since = "4.0.0")
495     public List<String> getTestCompileSourceRoots() {
496         return getSourceRootDirs(ProjectScope.TEST, Language.JAVA_FAMILY);
497     }
498 
499     // TODO let the scope handler deal with this
500     private static boolean isCompilePathElement(final String scope) {
501         return Artifact.SCOPE_COMPILE.equals(scope)
502                 || Artifact.SCOPE_PROVIDED.equals(scope)
503                 || Artifact.SCOPE_SYSTEM.equals(scope);
504     }
505 
506     // TODO let the scope handler deal with this
507     private static boolean isRuntimePathElement(final String scope) {
508         return Artifact.SCOPE_COMPILE.equals(scope) || Artifact.SCOPE_RUNTIME.equals(scope);
509     }
510 
511     // TODO let the scope handler deal with this
512     private static boolean isTestPathElement(final String scope) {
513         return true;
514     }
515 
516     /**
517      * Returns a filtered list of class path elements. This method is invoked when the caller
518      * requested that all dependencies are placed on the class path, with no module path element.
519      *
520      * @param scopeFilter a filter returning {@code true} for the artifact scopes to accept
521      * @param includeTestDir whether to include the test directory in the classpath elements
522      * @return paths of all artifacts placed on the classpath
523      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
524      */
525     private List<String> getClasspathElements(final Predicate<String> scopeFilter, final boolean includeTestDir)
526             throws DependencyResolutionRequiredException {
527         final List<String> list = new ArrayList<>(getArtifacts().size() + 2);
528         if (includeTestDir) {
529             String d = getBuild().getTestOutputDirectory();
530             if (d != null) {
531                 list.add(d);
532             }
533         }
534         String d = getBuild().getOutputDirectory();
535         if (d != null) {
536             list.add(d);
537         }
538         for (Artifact a : getArtifacts()) {
539             final File f = a.getFile();
540             if (f != null && scopeFilter.test(a.getScope())) {
541                 final ArtifactHandler h = a.getArtifactHandler();
542                 if (h.isAddedToClasspath()) {
543                     list.add(f.getPath());
544                 }
545             }
546         }
547         return list;
548     }
549 
550     /**
551      * Returns the elements placed on the classpath for compilation.
552      * This method can be invoked when the caller does not support module-path.
553      *
554      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
555      *
556      * @deprecated This method is unreliable because it does not consider other dependency properties.
557      * See {@link org.apache.maven.api.JavaPathType} instead for better analysis.
558      */
559     @Deprecated
560     public List<String> getCompileClasspathElements() throws DependencyResolutionRequiredException {
561         return getClasspathElements(MavenProject::isCompilePathElement, false);
562     }
563 
564     /**
565      * Returns the elements placed on the classpath for tests.
566      * This method can be invoked when the caller does not support module-path.
567      *
568      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
569      *
570      * @deprecated This method is unreliable because it does not consider other dependency properties.
571      * See {@link org.apache.maven.api.JavaPathType} instead for better analysis.
572      */
573     @Deprecated
574     public List<String> getTestClasspathElements() throws DependencyResolutionRequiredException {
575         return getClasspathElements(MavenProject::isTestPathElement, true);
576     }
577 
578     /**
579      * Returns the elements placed on the classpath for runtime.
580      * This method can be invoked when the caller does not support module-path.
581      *
582      * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved
583      *
584      * @deprecated This method is unreliable because it does not consider other dependency properties.
585      * See {@link org.apache.maven.api.JavaPathType} instead for better analysis.
586      */
587     @Deprecated
588     public List<String> getRuntimeClasspathElements() throws DependencyResolutionRequiredException {
589         return getClasspathElements(MavenProject::isRuntimePathElement, false);
590     }
591 
592     // ----------------------------------------------------------------------
593     // Delegate to the model
594     // ----------------------------------------------------------------------
595 
596     public void setModelVersion(String pomVersion) {
597         getModel().setModelVersion(pomVersion);
598     }
599 
600     public String getModelVersion() {
601         return getModel().getModelVersion();
602     }
603 
604     public String getId() {
605         return getModel().getId();
606     }
607 
608     public void setGroupId(String groupId) {
609         getModel().setGroupId(groupId);
610     }
611 
612     public String getGroupId() {
613         String groupId = getModel().getGroupId();
614 
615         if ((groupId == null) && (getModel().getParent() != null)) {
616             groupId = getModel().getParent().getGroupId();
617         }
618 
619         return groupId;
620     }
621 
622     public void setArtifactId(String artifactId) {
623         getModel().setArtifactId(artifactId);
624     }
625 
626     public String getArtifactId() {
627         return getModel().getArtifactId();
628     }
629 
630     public void setName(String name) {
631         getModel().setName(name);
632     }
633 
634     public String getName() {
635         // TODO this should not be allowed to be null.
636         if (getModel().getName() != null) {
637             return getModel().getName();
638         } else {
639             return getArtifactId();
640         }
641     }
642 
643     public void setVersion(String version) {
644         getModel().setVersion(version);
645     }
646 
647     public String getVersion() {
648         String version = getModel().getVersion();
649 
650         if ((version == null) && (getModel().getParent() != null)) {
651             version = getModel().getParent().getVersion();
652         }
653 
654         return version;
655     }
656 
657     public String getPackaging() {
658         return getModel().getPackaging();
659     }
660 
661     public void setPackaging(String packaging) {
662         getModel().setPackaging(packaging);
663     }
664 
665     public void setInceptionYear(String inceptionYear) {
666         getModel().setInceptionYear(inceptionYear);
667     }
668 
669     public String getInceptionYear() {
670         return getModel().getInceptionYear();
671     }
672 
673     public void setUrl(String url) {
674         getModel().setUrl(url);
675     }
676 
677     public String getUrl() {
678         return getModel().getUrl();
679     }
680 
681     public Prerequisites getPrerequisites() {
682         return getModel().getPrerequisites();
683     }
684 
685     public void setIssueManagement(IssueManagement issueManagement) {
686         getModel().setIssueManagement(issueManagement);
687     }
688 
689     public CiManagement getCiManagement() {
690         return getModel().getCiManagement();
691     }
692 
693     public void setCiManagement(CiManagement ciManagement) {
694         getModel().setCiManagement(ciManagement);
695     }
696 
697     public IssueManagement getIssueManagement() {
698         return getModel().getIssueManagement();
699     }
700 
701     public void setDistributionManagement(DistributionManagement distributionManagement) {
702         getModel().setDistributionManagement(distributionManagement);
703     }
704 
705     public DistributionManagement getDistributionManagement() {
706         return getModel().getDistributionManagement();
707     }
708 
709     public void setDescription(String description) {
710         getModel().setDescription(description);
711     }
712 
713     public String getDescription() {
714         return getModel().getDescription();
715     }
716 
717     public void setOrganization(Organization organization) {
718         getModel().setOrganization(organization);
719     }
720 
721     public Organization getOrganization() {
722         return getModel().getOrganization();
723     }
724 
725     public void setScm(Scm scm) {
726         getModel().setScm(scm);
727     }
728 
729     public Scm getScm() {
730         return getModel().getScm();
731     }
732 
733     public void setMailingLists(List<MailingList> mailingLists) {
734         getModel().setMailingLists(mailingLists);
735     }
736 
737     public List<MailingList> getMailingLists() {
738         return getModel().getMailingLists();
739     }
740 
741     public void addMailingList(MailingList mailingList) {
742         getModel().addMailingList(mailingList);
743     }
744 
745     public void setDevelopers(List<Developer> developers) {
746         getModel().setDevelopers(developers);
747     }
748 
749     public List<Developer> getDevelopers() {
750         return getModel().getDevelopers();
751     }
752 
753     public void addDeveloper(Developer developer) {
754         getModel().addDeveloper(developer);
755     }
756 
757     public void setContributors(List<Contributor> contributors) {
758         getModel().setContributors(contributors);
759     }
760 
761     public List<Contributor> getContributors() {
762         return getModel().getContributors();
763     }
764 
765     public void addContributor(Contributor contributor) {
766         getModel().addContributor(contributor);
767     }
768 
769     public void setBuild(Build build) {
770         getModel().setBuild(build);
771     }
772 
773     public Build getBuild() {
774         return getModelBuild();
775     }
776 
777     /**
778      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)}.
779      */
780     @Deprecated(since = "4.0.0")
781     public List<Resource> getResources() {
782         return getResources(ProjectScope.MAIN);
783     }
784 
785     /**
786      * @deprecated Replaced by {@code getEnabledSourceRoots(ProjectScope.TEST, Language.RESOURCES)}.
787      */
788     @Deprecated(since = "4.0.0")
789     public List<Resource> getTestResources() {
790         return getResources(ProjectScope.TEST);
791     }
792 
793     private List<Resource> getResources(final ProjectScope scope) {
794         return new AbstractSequentialList<>() {
795             private Stream<SourceRoot> sources() {
796                 return getEnabledSourceRoots(scope, Language.RESOURCES);
797             }
798 
799             @Override
800             public ListIterator<Resource> listIterator(int index) {
801                 return sources()
802                         .map(sourceRoot -> toConnectedResource(sourceRoot, scope))
803                         .toList()
804                         .listIterator(index);
805             }
806 
807             @Override
808             public int size() {
809                 return Math.toIntExact(sources().count());
810             }
811 
812             @Override
813             public boolean isEmpty() {
814                 return sources().findAny().isEmpty();
815             }
816 
817             @Override
818             public boolean add(Resource resource) {
819                 addResource(scope, resource);
820                 return true;
821             }
822         };
823     }
824 
825     private static Resource toResource(SourceRoot sourceRoot) {
826         return new Resource(org.apache.maven.api.model.Resource.newBuilder()
827                 .directory(sourceRoot.directory().toString())
828                 .includes(sourceRoot.includes())
829                 .excludes(sourceRoot.excludes())
830                 .filtering(Boolean.toString(sourceRoot.stringFiltering()))
831                 .targetPath(sourceRoot.targetPath().map(Path::toString).orElse(null))
832                 .build());
833     }
834 
835     private Resource toConnectedResource(SourceRoot sourceRoot, ProjectScope scope) {
836         return new ConnectedResource(sourceRoot, scope, this);
837     }
838 
839     private void addResource(ProjectScope scope, Resource resource) {
840         addSourceRoot(new DefaultSourceRoot(getBaseDirectory(), scope, resource.getDelegate()));
841     }
842 
843     /**
844      * @deprecated {@link Resource} is replaced by {@link SourceRoot}.
845      */
846     @Deprecated(since = "4.0.0")
847     public void addResource(Resource resource) {
848         addResource(ProjectScope.MAIN, resource);
849     }
850 
851     /**
852      * @deprecated {@link Resource} is replaced by {@link SourceRoot}.
853      */
854     @Deprecated(since = "4.0.0")
855     public void addTestResource(Resource testResource) {
856         addResource(ProjectScope.TEST, testResource);
857     }
858 
859     public void setLicenses(List<License> licenses) {
860         getModel().setLicenses(licenses);
861     }
862 
863     public List<License> getLicenses() {
864         return getModel().getLicenses();
865     }
866 
867     public void addLicense(License license) {
868         getModel().addLicense(license);
869     }
870 
871     public void setArtifacts(Set<Artifact> artifacts) {
872         this.artifacts = artifacts;
873 
874         // flush the calculated artifactMap
875         artifactMap = null;
876     }
877 
878     /**
879      * All dependencies that this project has, including transitive ones. Contents are lazily populated, so depending on
880      * what phases have run dependencies in some scopes won't be included. e.g. if only compile phase has run,
881      * dependencies with scope test won't be included.
882      *
883      * @return {@link Set} &lt; {@link Artifact} &gt;
884      * @see #getDependencyArtifacts() to get only direct dependencies
885      */
886     public Set<Artifact> getArtifacts() {
887         if (artifacts == null) {
888             if (artifactFilter == null || resolvedArtifacts == null) {
889                 artifacts = new LinkedHashSet<>();
890             } else {
891                 artifacts = new LinkedHashSet<>(resolvedArtifacts.size() * 2);
892                 for (Artifact artifact : resolvedArtifacts) {
893                     if (artifactFilter.include(artifact)) {
894                         artifacts.add(artifact);
895                     }
896                 }
897             }
898         }
899         return artifacts;
900     }
901 
902     public Map<String, Artifact> getArtifactMap() {
903         if (artifactMap == null) {
904             artifactMap = ArtifactUtils.artifactMapByVersionlessId(getArtifacts());
905         }
906         return artifactMap;
907     }
908 
909     public void setPluginArtifacts(Set<Artifact> pluginArtifacts) {
910         this.pluginArtifacts = pluginArtifacts;
911 
912         this.pluginArtifactMap = null;
913     }
914 
915     public Set<Artifact> getPluginArtifacts() {
916         return pluginArtifacts;
917     }
918 
919     public Map<String, Artifact> getPluginArtifactMap() {
920         if (pluginArtifactMap == null) {
921             pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getPluginArtifacts());
922         }
923 
924         return pluginArtifactMap;
925     }
926 
927     public void setParentArtifact(Artifact parentArtifact) {
928         this.parentArtifact = parentArtifact;
929     }
930 
931     public Artifact getParentArtifact() {
932         return parentArtifact;
933     }
934 
935     public List<Repository> getRepositories() {
936         return getModel().getRepositories();
937     }
938 
939     // ----------------------------------------------------------------------
940     // Plugins
941     // ----------------------------------------------------------------------
942 
943     public List<Plugin> getBuildPlugins() {
944         if (getModel().getBuild() == null) {
945             return Collections.emptyList();
946         }
947         return Collections.unmodifiableList(getModel().getBuild().getPlugins());
948     }
949 
950     public List<String> getModules() {
951         if (!getModel().getDelegate().getSubprojects().isEmpty()) {
952             return getModel().getDelegate().getSubprojects();
953         }
954         return getModel().getModules();
955     }
956 
957     public PluginManagement getPluginManagement() {
958         PluginManagement pluginMgmt = null;
959 
960         Build build = getModel().getBuild();
961         if (build != null) {
962             pluginMgmt = build.getPluginManagement();
963         }
964 
965         return pluginMgmt;
966     }
967 
968     private Build getModelBuild() {
969         Build build = getModel().getBuild();
970 
971         if (build == null) {
972             build = new Build();
973 
974             getModel().setBuild(build);
975         }
976 
977         return build;
978     }
979 
980     @Deprecated
981     public void setRemoteArtifactRepositories(List<ArtifactRepository> remoteArtifactRepositories) {
982         this.remoteArtifactRepositories = remoteArtifactRepositories;
983         this.remoteProjectRepositories = RepositoryUtils.toRepos(getRemoteArtifactRepositories());
984     }
985 
986     @Deprecated
987     public List<ArtifactRepository> getRemoteArtifactRepositories() {
988         if (remoteArtifactRepositories == null) {
989             remoteArtifactRepositories = new ArrayList<>();
990         }
991 
992         return remoteArtifactRepositories;
993     }
994 
995     @Deprecated
996     public void setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
997         this.pluginArtifactRepositories = pluginArtifactRepositories;
998         this.remotePluginRepositories = RepositoryUtils.toRepos(getPluginArtifactRepositories());
999     }
1000 
1001     /**
1002      * @return a list of ArtifactRepository objects constructed from the Repository objects returned by
1003      *         getPluginRepositories.
1004      */
1005     @Deprecated
1006     public List<ArtifactRepository> getPluginArtifactRepositories() {
1007         if (pluginArtifactRepositories == null) {
1008             pluginArtifactRepositories = new ArrayList<>();
1009         }
1010 
1011         return pluginArtifactRepositories;
1012     }
1013 
1014     @Deprecated
1015     public ArtifactRepository getDistributionManagementArtifactRepository() {
1016         return getArtifact().isSnapshot() && (getSnapshotArtifactRepository() != null)
1017                 ? getSnapshotArtifactRepository()
1018                 : getReleaseArtifactRepository();
1019     }
1020 
1021     public List<Repository> getPluginRepositories() {
1022         return getModel().getPluginRepositories();
1023     }
1024 
1025     public List<RemoteRepository> getRemoteProjectRepositories() {
1026         if (remoteProjectRepositories == null) {
1027             remoteProjectRepositories = new ArrayList<>();
1028         }
1029         return remoteProjectRepositories;
1030     }
1031 
1032     public List<RemoteRepository> getRemotePluginRepositories() {
1033         if (remotePluginRepositories == null) {
1034             remotePluginRepositories = new ArrayList<>();
1035         }
1036         return remotePluginRepositories;
1037     }
1038 
1039     public void setActiveProfiles(List<Profile> activeProfiles) {
1040         this.activeProfiles = activeProfiles;
1041     }
1042 
1043     public List<Profile> getActiveProfiles() {
1044         return activeProfiles;
1045     }
1046 
1047     public void setInjectedProfileIds(String source, List<String> injectedProfileIds) {
1048         if (injectedProfileIds != null) {
1049             this.injectedProfileIds.put(source, new ArrayList<>(injectedProfileIds));
1050         } else {
1051             this.injectedProfileIds.remove(source);
1052         }
1053     }
1054 
1055     /**
1056      * Gets the identifiers of all profiles that contributed to this project's effective model. This includes active
1057      * profiles from the project's POM and all its parent POMs as well as from external sources like the
1058      * {@code settings.xml}. The profile identifiers are grouped by the identifier of their source, e.g.
1059      * {@code <groupId>:<artifactId>:<version>} for a POM profile or {@code external} for profiles from the
1060      * {@code settings.xml}.
1061      *
1062      * @return The identifiers of all injected profiles, indexed by the source from which the profiles originated, never
1063      *         {@code null}.
1064      */
1065     public Map<String, List<String>> getInjectedProfileIds() {
1066         return this.injectedProfileIds;
1067     }
1068 
1069     /**
1070      * Add or replace an artifact. This method is now deprecated. Use the @{MavenProjectHelper} to attach artifacts to a
1071      * project. In spite of the 'throws' declaration on this API, this method has never thrown an exception since Maven
1072      * 3.0.x. Historically, it logged and ignored a second addition of the same g/a/v/c/t. Now it replaces the file for
1073      * the artifact, so that plugins (e.g. shade) can change the pathname of the file for a particular set of
1074      * coordinates.
1075      *
1076      * @param artifact the artifact to add or replace.
1077      * @deprecated Please use {@link MavenProjectHelper}
1078      * @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility
1079      */
1080     public void addAttachedArtifact(Artifact artifact) throws DuplicateArtifactAttachmentException {
1081         // if already there we remove it and add again
1082         int index = attachedArtifacts.indexOf(artifact);
1083         if (index >= 0) {
1084             LOGGER.warn("artifact '{}' already attached, replacing previous instance", artifact);
1085             attachedArtifacts.set(index, artifact);
1086         } else {
1087             attachedArtifacts.add(artifact);
1088         }
1089     }
1090 
1091     /**
1092      * Returns a read-only list of the attached artifacts to this project.
1093      *
1094      * @return the attached artifacts of this project
1095      */
1096     public List<Artifact> getAttachedArtifacts() {
1097         if (attachedArtifacts == null) {
1098             attachedArtifacts = new ArrayList<>();
1099         }
1100         return Collections.unmodifiableList(attachedArtifacts);
1101     }
1102 
1103     public Xpp3Dom getGoalConfiguration(
1104             String pluginGroupId, String pluginArtifactId, String executionId, String goalId) {
1105         Xpp3Dom dom = null;
1106 
1107         if (getBuildPlugins() != null) {
1108             for (Plugin plugin : getBuildPlugins()) {
1109                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1110                     dom = (Xpp3Dom) plugin.getConfiguration();
1111 
1112                     if (executionId != null) {
1113                         for (PluginExecution execution : plugin.getExecutions()) {
1114                             if (executionId.equals(execution.getId())) {
1115                                 // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
1116                                 dom = (Xpp3Dom) execution.getConfiguration();
1117                                 break;
1118                             }
1119                         }
1120                     }
1121                     break;
1122                 }
1123             }
1124         }
1125 
1126         if (dom != null) {
1127             // make a copy so the original in the POM doesn't get messed with
1128             dom = new Xpp3Dom(dom);
1129         }
1130 
1131         return dom;
1132     }
1133 
1134     public MavenProject getExecutionProject() {
1135         return (executionProject == null ? this : executionProject);
1136     }
1137 
1138     public void setExecutionProject(MavenProject executionProject) {
1139         this.executionProject = executionProject;
1140     }
1141 
1142     public List<MavenProject> getCollectedProjects() {
1143         return collectedProjects;
1144     }
1145 
1146     public void setCollectedProjects(List<MavenProject> collectedProjects) {
1147         this.collectedProjects = collectedProjects;
1148     }
1149 
1150     /**
1151      * Direct dependencies that this project has.
1152      *
1153      * @return {@link Set} &lt; {@link Artifact} &gt;
1154      * @see #getArtifacts() to get all transitive dependencies
1155      */
1156     @Deprecated
1157     public Set<Artifact> getDependencyArtifacts() {
1158         return dependencyArtifacts;
1159     }
1160 
1161     @Deprecated
1162     public void setDependencyArtifacts(Set<Artifact> dependencyArtifacts) {
1163         this.dependencyArtifacts = dependencyArtifacts;
1164     }
1165 
1166     @Deprecated
1167     public void setReleaseArtifactRepository(ArtifactRepository releaseArtifactRepository) {
1168         this.releaseArtifactRepository = releaseArtifactRepository;
1169     }
1170 
1171     @Deprecated
1172     public void setSnapshotArtifactRepository(ArtifactRepository snapshotArtifactRepository) {
1173         this.snapshotArtifactRepository = snapshotArtifactRepository;
1174     }
1175 
1176     public void setOriginalModel(Model originalModel) {
1177         this.originalModel = originalModel;
1178     }
1179 
1180     public Model getOriginalModel() {
1181         return originalModel;
1182     }
1183 
1184     public void setManagedVersionMap(Map<String, Artifact> map) {
1185         managedVersionMap = map;
1186     }
1187 
1188     public Map<String, Artifact> getManagedVersionMap() {
1189         return managedVersionMap;
1190     }
1191 
1192     @Override
1193     public boolean equals(Object other) {
1194         if (other == this) {
1195             return true;
1196         } else {
1197             if (other instanceof MavenProject that) {
1198                 return Objects.equals(getArtifactId(), that.getArtifactId())
1199                         && Objects.equals(getGroupId(), that.getGroupId())
1200                         && Objects.equals(getVersion(), that.getVersion());
1201             } else {
1202                 return false;
1203             }
1204         }
1205     }
1206 
1207     @Override
1208     public int hashCode() {
1209         return Objects.hash(getGroupId(), getArtifactId(), getVersion());
1210     }
1211 
1212     public List<Extension> getBuildExtensions() {
1213         Build build = getBuild();
1214         if ((build == null) || (build.getExtensions() == null)) {
1215             return Collections.emptyList();
1216         } else {
1217             return Collections.unmodifiableList(build.getExtensions());
1218         }
1219     }
1220 
1221     public void addProjectReference(MavenProject project) {
1222         projectReferences.put(
1223                 getProjectReferenceId(project.getGroupId(), project.getArtifactId(), project.getVersion()), project);
1224     }
1225 
1226     public Properties getProperties() {
1227         return getModel().getProperties();
1228     }
1229 
1230     public List<String> getFilters() {
1231         return getBuild().getFilters();
1232     }
1233 
1234     public Map<String, MavenProject> getProjectReferences() {
1235         return projectReferences;
1236     }
1237 
1238     public boolean isExecutionRoot() {
1239         return executionRoot;
1240     }
1241 
1242     public void setExecutionRoot(boolean executionRoot) {
1243         this.executionRoot = executionRoot;
1244     }
1245 
1246     public String getDefaultGoal() {
1247         return getBuild() != null ? getBuild().getDefaultGoal() : null;
1248     }
1249 
1250     public Plugin getPlugin(String pluginKey) {
1251         org.apache.maven.api.model.Plugin plugin =
1252                 getBuild().getDelegate().getPluginsAsMap().get(pluginKey);
1253         return plugin != null ? new Plugin(plugin, getBuild()) : null;
1254     }
1255 
1256     /**
1257      * Default toString
1258      */
1259     @Override
1260     public String toString() {
1261         StringBuilder sb = new StringBuilder(128);
1262         sb.append("MavenProject: ");
1263         sb.append(getGroupId());
1264         sb.append(':');
1265         sb.append(getArtifactId());
1266         sb.append(':');
1267         sb.append(getVersion());
1268         if (getFile() != null) {
1269             sb.append(" @ ");
1270             sb.append(getFile().getPath());
1271         }
1272 
1273         return sb.toString();
1274     }
1275 
1276     /**
1277      * @since 2.0.9
1278      */
1279     @Override
1280     public MavenProject clone() {
1281         MavenProject clone;
1282         try {
1283             clone = (MavenProject) super.clone();
1284         } catch (CloneNotSupportedException e) {
1285             throw new UnsupportedOperationException(e);
1286         }
1287 
1288         clone.deepCopy(this);
1289 
1290         return clone;
1291     }
1292 
1293     public void setModel(Model model) {
1294         this.model = model;
1295     }
1296 
1297     protected void setAttachedArtifacts(List<Artifact> attachedArtifacts) {
1298         this.attachedArtifacts = attachedArtifacts;
1299     }
1300 
1301     /**
1302      * @deprecated Used only for the implementation of deprecated methods.
1303      */
1304     @Deprecated
1305     private void setSourceRootDirs(ProjectScope scope, Language language, List<String> roots) {
1306         sources.removeIf((source) -> scope.equals(source.scope()) && language.equals(source.language()));
1307         Path directory = getBaseDirectory();
1308         for (String root : roots) {
1309             addSourceRoot(new DefaultSourceRoot(scope, language, directory.resolve(root)));
1310         }
1311     }
1312 
1313     /**
1314      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1315      */
1316     @Deprecated(since = "4.0.0")
1317     protected void setCompileSourceRoots(List<String> compileSourceRoots) {
1318         setSourceRootDirs(ProjectScope.MAIN, Language.JAVA_FAMILY, compileSourceRoots);
1319     }
1320 
1321     /**
1322      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1323      */
1324     @Deprecated(since = "4.0.0")
1325     protected void setTestCompileSourceRoots(List<String> testCompileSourceRoots) {
1326         setSourceRootDirs(ProjectScope.TEST, Language.JAVA_FAMILY, testCompileSourceRoots);
1327     }
1328 
1329     protected ArtifactRepository getReleaseArtifactRepository() {
1330         return releaseArtifactRepository;
1331     }
1332 
1333     protected ArtifactRepository getSnapshotArtifactRepository() {
1334         return snapshotArtifactRepository;
1335     }
1336 
1337     private void deepCopy(MavenProject project) {
1338         // disown the parent
1339 
1340         // copy fields
1341         file = project.file;
1342         basedir = project.basedir;
1343 
1344         // don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
1345         // sure!
1346         if (project.getDependencyArtifacts() != null) {
1347             setDependencyArtifacts(Collections.unmodifiableSet(project.getDependencyArtifacts()));
1348         }
1349 
1350         if (project.getArtifacts() != null) {
1351             setArtifacts(Collections.unmodifiableSet(project.getArtifacts()));
1352         }
1353 
1354         if (project.getParentFile() != null) {
1355             parentFile = new File(project.getParentFile().getAbsolutePath());
1356         }
1357 
1358         if (project.getPluginArtifacts() != null) {
1359             setPluginArtifacts(Collections.unmodifiableSet(project.getPluginArtifacts()));
1360         }
1361 
1362         if (project.getReportArtifacts() != null) {
1363             setReportArtifacts(Collections.unmodifiableSet(project.getReportArtifacts()));
1364         }
1365 
1366         if (project.getExtensionArtifacts() != null) {
1367             setExtensionArtifacts(Collections.unmodifiableSet(project.getExtensionArtifacts()));
1368         }
1369 
1370         setParentArtifact((project.getParentArtifact()));
1371 
1372         if (project.getRemoteArtifactRepositories() != null) {
1373             setRemoteArtifactRepositories(Collections.unmodifiableList(project.getRemoteArtifactRepositories()));
1374         }
1375 
1376         if (project.getPluginArtifactRepositories() != null) {
1377             setPluginArtifactRepositories(Collections.unmodifiableList(project.getPluginArtifactRepositories()));
1378         }
1379 
1380         if (project.getActiveProfiles() != null) {
1381             setActiveProfiles((Collections.unmodifiableList(project.getActiveProfiles())));
1382         }
1383 
1384         if (project.getAttachedArtifacts() != null) {
1385             // clone properties modifiable by plugins in a forked lifecycle
1386             setAttachedArtifacts(new ArrayList<>(project.getAttachedArtifacts()));
1387         }
1388 
1389         // This property is not handled like others as we don't use public API.
1390         // The whole implementation of this `deepCopy` method may need revision,
1391         // but it would be the topic for a separated commit.
1392         sources = new LinkedHashSet<>(project.sources);
1393 
1394         if (project.getModel() != null) {
1395             setModel(project.getModel().clone());
1396         }
1397 
1398         if (project.getOriginalModel() != null) {
1399             setOriginalModel(project.getOriginalModel());
1400         }
1401 
1402         setExecutionRoot(project.isExecutionRoot());
1403 
1404         if (project.getArtifact() != null) {
1405             setArtifact(ArtifactUtils.copyArtifact(project.getArtifact()));
1406         }
1407 
1408         if (project.getManagedVersionMap() != null) {
1409             setManagedVersionMap(project.getManagedVersionMap());
1410         }
1411 
1412         lifecyclePhases.addAll(project.lifecyclePhases);
1413     }
1414 
1415     private static String getProjectReferenceId(String groupId, String artifactId, String version) {
1416         StringBuilder buffer = new StringBuilder(128);
1417         buffer.append(groupId).append(':').append(artifactId).append(':').append(version);
1418         return buffer.toString();
1419     }
1420 
1421     /**
1422      * Sets the value of the context value of this project identified by the given key. If the supplied value is
1423      * <code>null</code>, the context value is removed from this project. Context values are intended to allow core
1424      * extensions to associate derived state with project instances.
1425      */
1426     public void setContextValue(String key, Object value) {
1427         if (context == null) {
1428             context = new HashMap<>();
1429         }
1430         if (value != null) {
1431             context.put(key, value);
1432         } else {
1433             context.remove(key);
1434         }
1435     }
1436 
1437     /**
1438      * Returns context value of this project associated with the given key or null if this project has no such value.
1439      */
1440     public Object getContextValue(String key) {
1441         if (context == null) {
1442             return null;
1443         }
1444         return context.get(key);
1445     }
1446 
1447     /**
1448      * Sets the project's class realm. <strong>Warning:</strong> This is an internal utility method that is only public
1449      * for technical reasons, it is not part of the public API. In particular, this method can be changed or deleted
1450      * without prior notice and must not be used by plugins.
1451      *
1452      * @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
1453      */
1454     public void setClassRealm(ClassRealm classRealm) {
1455         this.classRealm = classRealm;
1456     }
1457 
1458     /**
1459      * Gets the project's class realm. This class realm hosts the build extensions of the project.
1460      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1461      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1462      * used by plugins.
1463      *
1464      * @return The project's class realm or {@code null}.
1465      */
1466     public ClassRealm getClassRealm() {
1467         return classRealm;
1468     }
1469 
1470     /**
1471      * Sets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
1472      * This is an internal utility method that is only public for technical reasons, it is not part of the public API.
1473      * In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
1474      *
1475      * @param extensionDependencyFilter The dependency filter to apply to plugins, may be {@code null}.
1476      */
1477     public void setExtensionDependencyFilter(DependencyFilter extensionDependencyFilter) {
1478         this.extensionDependencyFilter = extensionDependencyFilter;
1479     }
1480 
1481     /**
1482      * Gets the dependency filter used to exclude shared extension artifacts from plugin realms.
1483      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1484      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1485      * used by plugins.
1486      *
1487      * @return The dependency filter or {@code null}.
1488      */
1489     public DependencyFilter getExtensionDependencyFilter() {
1490         return extensionDependencyFilter;
1491     }
1492 
1493     /**
1494      * Sets the transitive dependency artifacts that have been resolved/collected for this project.
1495      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1496      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1497      * used by plugins.
1498      *
1499      * @param artifacts The set of artifacts, may be {@code null}.
1500      */
1501     public void setResolvedArtifacts(Set<Artifact> artifacts) {
1502         this.resolvedArtifacts = (artifacts != null) ? artifacts : Collections.emptySet();
1503         this.artifacts = null;
1504         this.artifactMap = null;
1505     }
1506 
1507     /**
1508      * Sets the scope filter to select the artifacts being exposed to the currently executed mojo.
1509      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1510      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1511      * used by plugins.
1512      *
1513      * @param artifactFilter The artifact filter, may be {@code null} to exclude all artifacts.
1514      */
1515     public void setArtifactFilter(ArtifactFilter artifactFilter) {
1516         this.artifactFilter = artifactFilter;
1517         this.artifacts = null;
1518         this.artifactMap = null;
1519     }
1520 
1521     /**
1522      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1523      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1524      * used by plugins.
1525      *
1526      * @param phase The phase to check for, must not be {@code null}.
1527      * @return {@code true} if the phase has been seen.
1528      */
1529     public boolean hasLifecyclePhase(String phase) {
1530         return lifecyclePhases.contains(phase);
1531     }
1532 
1533     /**
1534      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1535      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1536      * used by plugins.
1537      *
1538      * @param lifecyclePhase The lifecycle phase to add, must not be {@code null}.
1539      */
1540     public void addLifecyclePhase(String lifecyclePhase) {
1541         lifecyclePhases.add(lifecyclePhase);
1542     }
1543 
1544     // ----------------------------------------------------------------------------------------------------------------
1545     //
1546     //
1547     // D E P R E C A T E D
1548     //
1549     //
1550     // ----------------------------------------------------------------------------------------------------------------
1551     //
1552     // Everything below will be removed for Maven 4.0.0
1553     //
1554     // ----------------------------------------------------------------------------------------------------------------
1555 
1556     private ProjectBuildingRequest projectBuilderConfiguration;
1557 
1558     private Map<String, String> moduleAdjustments;
1559 
1560     @Deprecated // This appears only to be used in test code
1561     public String getModulePathAdjustment(MavenProject moduleProject) throws IOException {
1562         // FIXME: This is hacky. What if module directory doesn't match artifactid, and parent
1563         // is coming from the repository??
1564         String module = moduleProject.getArtifactId();
1565 
1566         File moduleFile = moduleProject.getFile();
1567 
1568         if (moduleFile != null) {
1569             File moduleDir = moduleFile.getCanonicalFile().getParentFile();
1570 
1571             module = moduleDir.getName();
1572         }
1573 
1574         if (moduleAdjustments == null) {
1575             moduleAdjustments = new HashMap<>();
1576 
1577             List<String> modules = getModules();
1578             if (modules != null) {
1579                 for (String modulePath : modules) {
1580                     String moduleName = modulePath;
1581 
1582                     if (moduleName.endsWith("/") || moduleName.endsWith("\\")) {
1583                         moduleName = moduleName.substring(0, moduleName.length() - 1);
1584                     }
1585 
1586                     int lastSlash = moduleName.lastIndexOf('/');
1587 
1588                     if (lastSlash < 0) {
1589                         lastSlash = moduleName.lastIndexOf('\\');
1590                     }
1591 
1592                     String adjustment = null;
1593 
1594                     if (lastSlash > -1) {
1595                         moduleName = moduleName.substring(lastSlash + 1);
1596                         adjustment = modulePath.substring(0, lastSlash);
1597                     }
1598 
1599                     moduleAdjustments.put(moduleName, adjustment);
1600                 }
1601             }
1602         }
1603 
1604         return moduleAdjustments.get(module);
1605     }
1606 
1607     @Deprecated
1608     public Set<Artifact> createArtifacts(ArtifactFactory artifactFactory, String inheritedScope, ArtifactFilter filter)
1609             throws InvalidDependencyVersionException {
1610         return DefaultProjectArtifactFactory.createArtifacts(
1611                 artifactFactory, getModel().getDependencies(), inheritedScope, filter, this);
1612     }
1613 
1614     @Deprecated
1615     protected void setScriptSourceRoots(List<String> scriptSourceRoots) {
1616         setSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT, scriptSourceRoots);
1617     }
1618 
1619     @Deprecated
1620     public void addScriptSourceRoot(String path) {
1621         addSourceRoot(ProjectScope.MAIN, Language.SCRIPT, path);
1622     }
1623 
1624     @Deprecated
1625     public List<String> getScriptSourceRoots() {
1626         return getSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT);
1627     }
1628 
1629     @Deprecated
1630     public List<Artifact> getCompileArtifacts() {
1631         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1632 
1633         for (Artifact a : getArtifacts()) {
1634             // TODO classpath check doesn't belong here - that's the other method
1635             if (a.getArtifactHandler().isAddedToClasspath()) {
1636                 // TODO let the scope handler deal with this
1637                 if (isCompilePathElement(a.getScope())) {
1638                     list.add(a);
1639                 }
1640             }
1641         }
1642         return list;
1643     }
1644 
1645     @Deprecated
1646     public List<Dependency> getCompileDependencies() {
1647         Set<Artifact> artifacts = getArtifacts();
1648 
1649         if ((artifacts == null) || artifacts.isEmpty()) {
1650             return Collections.emptyList();
1651         }
1652 
1653         List<Dependency> list = new ArrayList<>(artifacts.size());
1654 
1655         for (Artifact a : getArtifacts()) {
1656             // TODO let the scope handler deal with this
1657             if (isCompilePathElement(a.getScope())) {
1658                 Dependency dependency = new Dependency();
1659 
1660                 dependency.setArtifactId(a.getArtifactId());
1661                 dependency.setGroupId(a.getGroupId());
1662                 dependency.setVersion(a.getVersion());
1663                 dependency.setScope(a.getScope());
1664                 dependency.setType(a.getType());
1665                 dependency.setClassifier(a.getClassifier());
1666 
1667                 list.add(dependency);
1668             }
1669         }
1670         return Collections.unmodifiableList(list);
1671     }
1672 
1673     @Deprecated
1674     public List<Artifact> getTestArtifacts() {
1675         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1676 
1677         for (Artifact a : getArtifacts()) {
1678             // TODO classpath check doesn't belong here - that's the other method
1679             if (a.getArtifactHandler().isAddedToClasspath()) {
1680                 list.add(a);
1681             }
1682         }
1683         return list;
1684     }
1685 
1686     @Deprecated
1687     public List<Dependency> getTestDependencies() {
1688         Set<Artifact> artifacts = getArtifacts();
1689 
1690         if ((artifacts == null) || artifacts.isEmpty()) {
1691             return Collections.emptyList();
1692         }
1693 
1694         List<Dependency> list = new ArrayList<>(artifacts.size());
1695 
1696         for (Artifact a : getArtifacts()) {
1697             Dependency dependency = new Dependency();
1698 
1699             dependency.setArtifactId(a.getArtifactId());
1700             dependency.setGroupId(a.getGroupId());
1701             dependency.setVersion(a.getVersion());
1702             dependency.setScope(a.getScope());
1703             dependency.setType(a.getType());
1704             dependency.setClassifier(a.getClassifier());
1705 
1706             list.add(dependency);
1707         }
1708         return Collections.unmodifiableList(list);
1709     }
1710 
1711     @Deprecated // used by the Maven ITs
1712     public List<Dependency> getRuntimeDependencies() {
1713         Set<Artifact> artifacts = getArtifacts();
1714 
1715         if ((artifacts == null) || artifacts.isEmpty()) {
1716             return Collections.emptyList();
1717         }
1718 
1719         List<Dependency> list = new ArrayList<>(artifacts.size());
1720 
1721         for (Artifact a : getArtifacts()) {
1722             // TODO let the scope handler deal with this
1723             if (isRuntimePathElement(a.getScope())) {
1724                 Dependency dependency = new Dependency();
1725 
1726                 dependency.setArtifactId(a.getArtifactId());
1727                 dependency.setGroupId(a.getGroupId());
1728                 dependency.setVersion(a.getVersion());
1729                 dependency.setScope(a.getScope());
1730                 dependency.setType(a.getType());
1731                 dependency.setClassifier(a.getClassifier());
1732 
1733                 list.add(dependency);
1734             }
1735         }
1736         return Collections.unmodifiableList(list);
1737     }
1738 
1739     @Deprecated
1740     public List<Artifact> getRuntimeArtifacts() {
1741         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1742 
1743         for (Artifact a : getArtifacts()) {
1744             // TODO classpath check doesn't belong here - that's the other method
1745             if (a.getArtifactHandler().isAddedToClasspath() && isRuntimePathElement(a.getScope())) {
1746                 list.add(a);
1747             }
1748         }
1749         return list;
1750     }
1751 
1752     @Deprecated
1753     public List<String> getSystemClasspathElements() throws DependencyResolutionRequiredException {
1754         List<String> list = new ArrayList<>(getArtifacts().size());
1755 
1756         String d = getBuild().getOutputDirectory();
1757         if (d != null) {
1758             list.add(d);
1759         }
1760 
1761         for (Artifact a : getArtifacts()) {
1762             if (a.getArtifactHandler().isAddedToClasspath()) {
1763                 // TODO let the scope handler deal with this
1764                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1765                     File f = a.getFile();
1766                     if (f != null) {
1767                         list.add(f.getPath());
1768                     }
1769                 }
1770             }
1771         }
1772         return list;
1773     }
1774 
1775     @Deprecated
1776     public List<Artifact> getSystemArtifacts() {
1777         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1778 
1779         for (Artifact a : getArtifacts()) {
1780             // TODO classpath check doesn't belong here - that's the other method
1781             if (a.getArtifactHandler().isAddedToClasspath()) {
1782                 // TODO let the scope handler deal with this
1783                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1784                     list.add(a);
1785                 }
1786             }
1787         }
1788         return list;
1789     }
1790 
1791     @Deprecated
1792     public List<Dependency> getSystemDependencies() {
1793         Set<Artifact> artifacts = getArtifacts();
1794 
1795         if ((artifacts == null) || artifacts.isEmpty()) {
1796             return Collections.emptyList();
1797         }
1798 
1799         List<Dependency> list = new ArrayList<>(artifacts.size());
1800 
1801         for (Artifact a : getArtifacts()) {
1802             // TODO let the scope handler deal with this
1803             if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1804                 Dependency dependency = new Dependency();
1805 
1806                 dependency.setArtifactId(a.getArtifactId());
1807                 dependency.setGroupId(a.getGroupId());
1808                 dependency.setVersion(a.getVersion());
1809                 dependency.setScope(a.getScope());
1810                 dependency.setType(a.getType());
1811                 dependency.setClassifier(a.getClassifier());
1812 
1813                 list.add(dependency);
1814             }
1815         }
1816         return Collections.unmodifiableList(list);
1817     }
1818 
1819     @Deprecated
1820     public void setReporting(Reporting reporting) {
1821         getModel().setReporting(reporting);
1822     }
1823 
1824     @Deprecated
1825     public Reporting getReporting() {
1826         return getModel().getReporting();
1827     }
1828 
1829     @Deprecated
1830     public void setReportArtifacts(Set<Artifact> reportArtifacts) {
1831         this.reportArtifacts = reportArtifacts;
1832 
1833         reportArtifactMap = null;
1834     }
1835 
1836     @Deprecated
1837     public Set<Artifact> getReportArtifacts() {
1838         return reportArtifacts;
1839     }
1840 
1841     @Deprecated
1842     public Map<String, Artifact> getReportArtifactMap() {
1843         if (reportArtifactMap == null) {
1844             reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getReportArtifacts());
1845         }
1846 
1847         return reportArtifactMap;
1848     }
1849 
1850     @Deprecated
1851     public void setExtensionArtifacts(Set<Artifact> extensionArtifacts) {
1852         this.extensionArtifacts = extensionArtifacts;
1853         extensionArtifactMap = null;
1854     }
1855 
1856     @Deprecated
1857     public Set<Artifact> getExtensionArtifacts() {
1858         return extensionArtifacts;
1859     }
1860 
1861     @Deprecated
1862     public Map<String, Artifact> getExtensionArtifactMap() {
1863         if (extensionArtifactMap == null) {
1864             extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getExtensionArtifacts());
1865         }
1866 
1867         return extensionArtifactMap;
1868     }
1869 
1870     @Deprecated
1871     public List<ReportPlugin> getReportPlugins() {
1872         if (getModel().getReporting() == null) {
1873             return Collections.emptyList();
1874         }
1875         return Collections.unmodifiableList(getModel().getReporting().getPlugins());
1876     }
1877 
1878     @Deprecated
1879     public Xpp3Dom getReportConfiguration(String pluginGroupId, String pluginArtifactId, String reportSetId) {
1880         Xpp3Dom dom = null;
1881 
1882         // ----------------------------------------------------------------------
1883         // I would like to be able to look up the Mojo object using a key but
1884         // we have a limitation in modello that will be remedied shortly. So
1885         // for now I have to iterate through and see what we have.
1886         // ----------------------------------------------------------------------
1887 
1888         if (getReportPlugins() != null) {
1889             for (ReportPlugin plugin : getReportPlugins()) {
1890                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1891                     dom = (Xpp3Dom) plugin.getConfiguration();
1892 
1893                     if (reportSetId != null) {
1894                         ReportSet reportSet = plugin.getReportSetsAsMap().get(reportSetId);
1895                         if (reportSet != null) {
1896                             Xpp3Dom executionConfiguration = (Xpp3Dom) reportSet.getConfiguration();
1897                             if (executionConfiguration != null) {
1898                                 Xpp3Dom newDom = new Xpp3Dom(executionConfiguration);
1899                                 dom = Xpp3Dom.mergeXpp3Dom(newDom, dom);
1900                             }
1901                         }
1902                     }
1903                     break;
1904                 }
1905             }
1906         }
1907 
1908         if (dom != null) {
1909             // make a copy so the original in the POM doesn't get messed with
1910             dom = new Xpp3Dom(dom);
1911         }
1912 
1913         return dom;
1914     }
1915 
1916     /**
1917      * @deprecated Use MavenProjectHelper.attachArtifact(..) instead.
1918      */
1919     @Deprecated
1920     public void attachArtifact(String type, String classifier, File file) {}
1921 
1922     /**
1923      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1924      */
1925     @Deprecated
1926     public void writeModel(Writer writer) throws IOException {
1927         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1928         pomWriter.write(writer, getModel());
1929     }
1930 
1931     /**
1932      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1933      */
1934     @Deprecated
1935     public void writeOriginalModel(Writer writer) throws IOException {
1936         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1937         pomWriter.write(writer, getOriginalModel());
1938     }
1939 
1940     @Deprecated
1941     public Artifact replaceWithActiveArtifact(Artifact pluginArtifact) {
1942         return pluginArtifact;
1943     }
1944 
1945     /**
1946      * Gets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1947      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1948      *
1949      * @return The project building request or {@code null}.
1950      * @since 2.1
1951      */
1952     @Deprecated
1953     public ProjectBuildingRequest getProjectBuildingRequest() {
1954         return projectBuilderConfiguration;
1955     }
1956 
1957     /**
1958      * Sets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1959      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1960      *
1961      * @param projectBuildingRequest The project building request, may be {@code null}.
1962      * @since 2.1
1963      */
1964     // used by maven-dependency-tree
1965     @Deprecated
1966     public void setProjectBuildingRequest(ProjectBuildingRequest projectBuildingRequest) {
1967         this.projectBuilderConfiguration = projectBuildingRequest;
1968     }
1969 
1970     /**
1971      * @since 4.0.0
1972      * @return the rootDirectory for this project
1973      * @throws IllegalStateException if the rootDirectory cannot be found
1974      */
1975     public Path getRootDirectory() {
1976         if (rootDirectory == null) {
1977             throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
1978         }
1979         return rootDirectory;
1980     }
1981 
1982     public void setRootDirectory(Path rootDirectory) {
1983         this.rootDirectory = rootDirectory;
1984     }
1985 }