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         // Also update the model's Build to maintain compatibility with code that
842         // accesses resources via project.getBuild().getResources()
843         if (scope == ProjectScope.MAIN) {
844             getModelBuild().addResource(resource);
845         } else {
846             getModelBuild().addTestResource(resource);
847         }
848     }
849 
850     /**
851      * Syncs {@code Build.resources/testResources} from the {@code sources} set
852      * for Maven 3 plugin compatibility (e.g. when resources come from {@code <sources>}).
853      */
854     void syncBuildResources() {
855         getModelBuild().setResources(new java.util.ArrayList<>(getResources()));
856         getModelBuild().setTestResources(new java.util.ArrayList<>(getTestResources()));
857     }
858 
859     /** @deprecated {@link Resource} is replaced by {@link SourceRoot}. */
860     @Deprecated(since = "4.0.0")
861     public void addResource(Resource resource) {
862         addResource(ProjectScope.MAIN, resource);
863     }
864 
865     /** @deprecated {@link Resource} is replaced by {@link SourceRoot}. */
866     @Deprecated(since = "4.0.0")
867     public void addTestResource(Resource testResource) {
868         addResource(ProjectScope.TEST, testResource);
869     }
870 
871     public void setLicenses(List<License> licenses) {
872         getModel().setLicenses(licenses);
873     }
874 
875     public List<License> getLicenses() {
876         return getModel().getLicenses();
877     }
878 
879     public void addLicense(License license) {
880         getModel().addLicense(license);
881     }
882 
883     public void setArtifacts(Set<Artifact> artifacts) {
884         this.artifacts = artifacts;
885 
886         // flush the calculated artifactMap
887         artifactMap = null;
888     }
889 
890     /**
891      * All dependencies that this project has, including transitive ones. Contents are lazily populated, so depending on
892      * what phases have run dependencies in some scopes won't be included. e.g. if only compile phase has run,
893      * dependencies with scope test won't be included.
894      *
895      * @return {@link Set} &lt; {@link Artifact} &gt;
896      * @see #getDependencyArtifacts() to get only direct dependencies
897      */
898     public Set<Artifact> getArtifacts() {
899         if (artifacts == null) {
900             if (artifactFilter == null || resolvedArtifacts == null) {
901                 artifacts = new LinkedHashSet<>();
902             } else {
903                 artifacts = new LinkedHashSet<>(resolvedArtifacts.size() * 2);
904                 for (Artifact artifact : resolvedArtifacts) {
905                     if (artifactFilter.include(artifact)) {
906                         artifacts.add(artifact);
907                     }
908                 }
909             }
910         }
911         return artifacts;
912     }
913 
914     public Map<String, Artifact> getArtifactMap() {
915         if (artifactMap == null) {
916             artifactMap = ArtifactUtils.artifactMapByVersionlessId(getArtifacts());
917         }
918         return artifactMap;
919     }
920 
921     public void setPluginArtifacts(Set<Artifact> pluginArtifacts) {
922         this.pluginArtifacts = pluginArtifacts;
923 
924         this.pluginArtifactMap = null;
925     }
926 
927     public Set<Artifact> getPluginArtifacts() {
928         return pluginArtifacts;
929     }
930 
931     public Map<String, Artifact> getPluginArtifactMap() {
932         if (pluginArtifactMap == null) {
933             pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getPluginArtifacts());
934         }
935 
936         return pluginArtifactMap;
937     }
938 
939     public void setParentArtifact(Artifact parentArtifact) {
940         this.parentArtifact = parentArtifact;
941     }
942 
943     public Artifact getParentArtifact() {
944         return parentArtifact;
945     }
946 
947     public List<Repository> getRepositories() {
948         return getModel().getRepositories();
949     }
950 
951     // ----------------------------------------------------------------------
952     // Plugins
953     // ----------------------------------------------------------------------
954 
955     public List<Plugin> getBuildPlugins() {
956         if (getModel().getBuild() == null) {
957             return Collections.emptyList();
958         }
959         return Collections.unmodifiableList(getModel().getBuild().getPlugins());
960     }
961 
962     public List<String> getModules() {
963         if (!getModel().getDelegate().getSubprojects().isEmpty()) {
964             return getModel().getDelegate().getSubprojects();
965         }
966         return getModel().getModules();
967     }
968 
969     public PluginManagement getPluginManagement() {
970         PluginManagement pluginMgmt = null;
971 
972         Build build = getModel().getBuild();
973         if (build != null) {
974             pluginMgmt = build.getPluginManagement();
975         }
976 
977         return pluginMgmt;
978     }
979 
980     private Build getModelBuild() {
981         Build build = getModel().getBuild();
982 
983         if (build == null) {
984             build = new Build();
985 
986             getModel().setBuild(build);
987         }
988 
989         return build;
990     }
991 
992     @Deprecated
993     public void setRemoteArtifactRepositories(List<ArtifactRepository> remoteArtifactRepositories) {
994         this.remoteArtifactRepositories = remoteArtifactRepositories;
995         this.remoteProjectRepositories = RepositoryUtils.toRepos(getRemoteArtifactRepositories());
996     }
997 
998     @Deprecated
999     public List<ArtifactRepository> getRemoteArtifactRepositories() {
1000         if (remoteArtifactRepositories == null) {
1001             remoteArtifactRepositories = new ArrayList<>();
1002         }
1003 
1004         return remoteArtifactRepositories;
1005     }
1006 
1007     @Deprecated
1008     public void setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
1009         this.pluginArtifactRepositories = pluginArtifactRepositories;
1010         this.remotePluginRepositories = RepositoryUtils.toRepos(getPluginArtifactRepositories());
1011     }
1012 
1013     /**
1014      * @return a list of ArtifactRepository objects constructed from the Repository objects returned by
1015      *         getPluginRepositories.
1016      */
1017     @Deprecated
1018     public List<ArtifactRepository> getPluginArtifactRepositories() {
1019         if (pluginArtifactRepositories == null) {
1020             pluginArtifactRepositories = new ArrayList<>();
1021         }
1022 
1023         return pluginArtifactRepositories;
1024     }
1025 
1026     @Deprecated
1027     public ArtifactRepository getDistributionManagementArtifactRepository() {
1028         return getArtifact().isSnapshot() && (getSnapshotArtifactRepository() != null)
1029                 ? getSnapshotArtifactRepository()
1030                 : getReleaseArtifactRepository();
1031     }
1032 
1033     public List<Repository> getPluginRepositories() {
1034         return getModel().getPluginRepositories();
1035     }
1036 
1037     public List<RemoteRepository> getRemoteProjectRepositories() {
1038         if (remoteProjectRepositories == null) {
1039             remoteProjectRepositories = new ArrayList<>();
1040         }
1041         return remoteProjectRepositories;
1042     }
1043 
1044     public List<RemoteRepository> getRemotePluginRepositories() {
1045         if (remotePluginRepositories == null) {
1046             remotePluginRepositories = new ArrayList<>();
1047         }
1048         return remotePluginRepositories;
1049     }
1050 
1051     public void setActiveProfiles(List<Profile> activeProfiles) {
1052         this.activeProfiles = activeProfiles;
1053     }
1054 
1055     public List<Profile> getActiveProfiles() {
1056         return activeProfiles;
1057     }
1058 
1059     public void setInjectedProfileIds(String source, List<String> injectedProfileIds) {
1060         if (injectedProfileIds != null) {
1061             this.injectedProfileIds.put(source, new ArrayList<>(injectedProfileIds));
1062         } else {
1063             this.injectedProfileIds.remove(source);
1064         }
1065     }
1066 
1067     /**
1068      * Gets the identifiers of all profiles that contributed to this project's effective model. This includes active
1069      * profiles from the project's POM and all its parent POMs as well as from external sources like the
1070      * {@code settings.xml}. The profile identifiers are grouped by the identifier of their source, e.g.
1071      * {@code <groupId>:<artifactId>:<version>} for a POM profile or {@code external} for profiles from the
1072      * {@code settings.xml}.
1073      *
1074      * @return The identifiers of all injected profiles, indexed by the source from which the profiles originated, never
1075      *         {@code null}.
1076      */
1077     public Map<String, List<String>> getInjectedProfileIds() {
1078         return this.injectedProfileIds;
1079     }
1080 
1081     /**
1082      * Add or replace an artifact. This method is now deprecated. Use the @{MavenProjectHelper} to attach artifacts to a
1083      * project. In spite of the 'throws' declaration on this API, this method has never thrown an exception since Maven
1084      * 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
1085      * the artifact, so that plugins (e.g. shade) can change the pathname of the file for a particular set of
1086      * coordinates.
1087      *
1088      * @param artifact the artifact to add or replace.
1089      * @deprecated Please use {@link MavenProjectHelper}
1090      * @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility
1091      */
1092     public void addAttachedArtifact(Artifact artifact) throws DuplicateArtifactAttachmentException {
1093         // if already there we remove it and add again
1094         int index = attachedArtifacts.indexOf(artifact);
1095         if (index >= 0) {
1096             LOGGER.warn("artifact '{}' already attached, replacing previous instance", artifact);
1097             attachedArtifacts.set(index, artifact);
1098         } else {
1099             attachedArtifacts.add(artifact);
1100         }
1101     }
1102 
1103     /**
1104      * Returns a read-only list of the attached artifacts to this project.
1105      *
1106      * @return the attached artifacts of this project
1107      */
1108     public List<Artifact> getAttachedArtifacts() {
1109         if (attachedArtifacts == null) {
1110             attachedArtifacts = new ArrayList<>();
1111         }
1112         return Collections.unmodifiableList(attachedArtifacts);
1113     }
1114 
1115     public Xpp3Dom getGoalConfiguration(
1116             String pluginGroupId, String pluginArtifactId, String executionId, String goalId) {
1117         Xpp3Dom dom = null;
1118 
1119         if (getBuildPlugins() != null) {
1120             for (Plugin plugin : getBuildPlugins()) {
1121                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1122                     dom = (Xpp3Dom) plugin.getConfiguration();
1123 
1124                     if (executionId != null) {
1125                         for (PluginExecution execution : plugin.getExecutions()) {
1126                             if (executionId.equals(execution.getId())) {
1127                                 // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
1128                                 dom = (Xpp3Dom) execution.getConfiguration();
1129                                 break;
1130                             }
1131                         }
1132                     }
1133                     break;
1134                 }
1135             }
1136         }
1137 
1138         if (dom != null) {
1139             // make a copy so the original in the POM doesn't get messed with
1140             dom = new Xpp3Dom(dom);
1141         }
1142 
1143         return dom;
1144     }
1145 
1146     public MavenProject getExecutionProject() {
1147         return (executionProject == null ? this : executionProject);
1148     }
1149 
1150     public void setExecutionProject(MavenProject executionProject) {
1151         this.executionProject = executionProject;
1152     }
1153 
1154     public List<MavenProject> getCollectedProjects() {
1155         return collectedProjects;
1156     }
1157 
1158     public void setCollectedProjects(List<MavenProject> collectedProjects) {
1159         this.collectedProjects = collectedProjects;
1160     }
1161 
1162     /**
1163      * Direct dependencies that this project has.
1164      *
1165      * @return {@link Set} &lt; {@link Artifact} &gt;
1166      * @see #getArtifacts() to get all transitive dependencies
1167      */
1168     @Deprecated
1169     public Set<Artifact> getDependencyArtifacts() {
1170         return dependencyArtifacts;
1171     }
1172 
1173     @Deprecated
1174     public void setDependencyArtifacts(Set<Artifact> dependencyArtifacts) {
1175         this.dependencyArtifacts = dependencyArtifacts;
1176     }
1177 
1178     @Deprecated
1179     public void setReleaseArtifactRepository(ArtifactRepository releaseArtifactRepository) {
1180         this.releaseArtifactRepository = releaseArtifactRepository;
1181     }
1182 
1183     @Deprecated
1184     public void setSnapshotArtifactRepository(ArtifactRepository snapshotArtifactRepository) {
1185         this.snapshotArtifactRepository = snapshotArtifactRepository;
1186     }
1187 
1188     public void setOriginalModel(Model originalModel) {
1189         this.originalModel = originalModel;
1190     }
1191 
1192     public Model getOriginalModel() {
1193         return originalModel;
1194     }
1195 
1196     public void setManagedVersionMap(Map<String, Artifact> map) {
1197         managedVersionMap = map;
1198     }
1199 
1200     public Map<String, Artifact> getManagedVersionMap() {
1201         return managedVersionMap;
1202     }
1203 
1204     @Override
1205     public boolean equals(Object other) {
1206         if (other == this) {
1207             return true;
1208         } else {
1209             if (other instanceof MavenProject that) {
1210                 return Objects.equals(getArtifactId(), that.getArtifactId())
1211                         && Objects.equals(getGroupId(), that.getGroupId())
1212                         && Objects.equals(getVersion(), that.getVersion());
1213             } else {
1214                 return false;
1215             }
1216         }
1217     }
1218 
1219     @Override
1220     public int hashCode() {
1221         return Objects.hash(getGroupId(), getArtifactId(), getVersion());
1222     }
1223 
1224     public List<Extension> getBuildExtensions() {
1225         Build build = getBuild();
1226         if ((build == null) || (build.getExtensions() == null)) {
1227             return Collections.emptyList();
1228         } else {
1229             return Collections.unmodifiableList(build.getExtensions());
1230         }
1231     }
1232 
1233     public void addProjectReference(MavenProject project) {
1234         projectReferences.put(
1235                 getProjectReferenceId(project.getGroupId(), project.getArtifactId(), project.getVersion()), project);
1236     }
1237 
1238     public Properties getProperties() {
1239         return getModel().getProperties();
1240     }
1241 
1242     public List<String> getFilters() {
1243         return getBuild().getFilters();
1244     }
1245 
1246     public Map<String, MavenProject> getProjectReferences() {
1247         return projectReferences;
1248     }
1249 
1250     public boolean isExecutionRoot() {
1251         return executionRoot;
1252     }
1253 
1254     public void setExecutionRoot(boolean executionRoot) {
1255         this.executionRoot = executionRoot;
1256     }
1257 
1258     public String getDefaultGoal() {
1259         return getBuild() != null ? getBuild().getDefaultGoal() : null;
1260     }
1261 
1262     public Plugin getPlugin(String pluginKey) {
1263         org.apache.maven.api.model.Plugin plugin =
1264                 getBuild().getDelegate().getPluginsAsMap().get(pluginKey);
1265         return plugin != null ? new Plugin(plugin, getBuild()) : null;
1266     }
1267 
1268     /**
1269      * Default toString
1270      */
1271     @Override
1272     public String toString() {
1273         StringBuilder sb = new StringBuilder(128);
1274         sb.append("MavenProject: ");
1275         sb.append(getGroupId());
1276         sb.append(':');
1277         sb.append(getArtifactId());
1278         sb.append(':');
1279         sb.append(getVersion());
1280         if (getFile() != null) {
1281             sb.append(" @ ");
1282             sb.append(getFile().getPath());
1283         }
1284 
1285         return sb.toString();
1286     }
1287 
1288     /**
1289      * @since 2.0.9
1290      */
1291     @Override
1292     public MavenProject clone() {
1293         MavenProject clone;
1294         try {
1295             clone = (MavenProject) super.clone();
1296         } catch (CloneNotSupportedException e) {
1297             throw new UnsupportedOperationException(e);
1298         }
1299 
1300         clone.deepCopy(this);
1301 
1302         return clone;
1303     }
1304 
1305     public void setModel(Model model) {
1306         this.model = model;
1307     }
1308 
1309     protected void setAttachedArtifacts(List<Artifact> attachedArtifacts) {
1310         this.attachedArtifacts = attachedArtifacts;
1311     }
1312 
1313     /**
1314      * @deprecated Used only for the implementation of deprecated methods.
1315      */
1316     @Deprecated
1317     private void setSourceRootDirs(ProjectScope scope, Language language, List<String> roots) {
1318         sources.removeIf((source) -> scope.equals(source.scope()) && language.equals(source.language()));
1319         Path directory = getBaseDirectory();
1320         for (String root : roots) {
1321             addSourceRoot(new DefaultSourceRoot(scope, language, directory.resolve(root)));
1322         }
1323     }
1324 
1325     /**
1326      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1327      */
1328     @Deprecated(since = "4.0.0")
1329     protected void setCompileSourceRoots(List<String> compileSourceRoots) {
1330         setSourceRootDirs(ProjectScope.MAIN, Language.JAVA_FAMILY, compileSourceRoots);
1331     }
1332 
1333     /**
1334      * @deprecated Replaced by {@link #addSourceRoot(ProjectScope, Language, String)}.
1335      */
1336     @Deprecated(since = "4.0.0")
1337     protected void setTestCompileSourceRoots(List<String> testCompileSourceRoots) {
1338         setSourceRootDirs(ProjectScope.TEST, Language.JAVA_FAMILY, testCompileSourceRoots);
1339     }
1340 
1341     protected ArtifactRepository getReleaseArtifactRepository() {
1342         return releaseArtifactRepository;
1343     }
1344 
1345     protected ArtifactRepository getSnapshotArtifactRepository() {
1346         return snapshotArtifactRepository;
1347     }
1348 
1349     private void deepCopy(MavenProject project) {
1350         // disown the parent
1351 
1352         // copy fields
1353         file = project.file;
1354         basedir = project.basedir;
1355 
1356         // don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
1357         // sure!
1358         if (project.getDependencyArtifacts() != null) {
1359             setDependencyArtifacts(Collections.unmodifiableSet(project.getDependencyArtifacts()));
1360         }
1361 
1362         if (project.getArtifacts() != null) {
1363             setArtifacts(Collections.unmodifiableSet(project.getArtifacts()));
1364         }
1365 
1366         if (project.getParentFile() != null) {
1367             parentFile = new File(project.getParentFile().getAbsolutePath());
1368         }
1369 
1370         if (project.getPluginArtifacts() != null) {
1371             setPluginArtifacts(Collections.unmodifiableSet(project.getPluginArtifacts()));
1372         }
1373 
1374         if (project.getReportArtifacts() != null) {
1375             setReportArtifacts(Collections.unmodifiableSet(project.getReportArtifacts()));
1376         }
1377 
1378         if (project.getExtensionArtifacts() != null) {
1379             setExtensionArtifacts(Collections.unmodifiableSet(project.getExtensionArtifacts()));
1380         }
1381 
1382         setParentArtifact((project.getParentArtifact()));
1383 
1384         if (project.getRemoteArtifactRepositories() != null) {
1385             setRemoteArtifactRepositories(Collections.unmodifiableList(project.getRemoteArtifactRepositories()));
1386         }
1387 
1388         if (project.getPluginArtifactRepositories() != null) {
1389             setPluginArtifactRepositories(Collections.unmodifiableList(project.getPluginArtifactRepositories()));
1390         }
1391 
1392         if (project.getActiveProfiles() != null) {
1393             setActiveProfiles((Collections.unmodifiableList(project.getActiveProfiles())));
1394         }
1395 
1396         if (project.getAttachedArtifacts() != null) {
1397             // clone properties modifiable by plugins in a forked lifecycle
1398             setAttachedArtifacts(new ArrayList<>(project.getAttachedArtifacts()));
1399         }
1400 
1401         // This property is not handled like others as we don't use public API.
1402         // The whole implementation of this `deepCopy` method may need revision,
1403         // but it would be the topic for a separated commit.
1404         sources = new LinkedHashSet<>(project.sources);
1405 
1406         if (project.getModel() != null) {
1407             setModel(project.getModel().clone());
1408         }
1409 
1410         if (project.getOriginalModel() != null) {
1411             setOriginalModel(project.getOriginalModel());
1412         }
1413 
1414         setExecutionRoot(project.isExecutionRoot());
1415 
1416         if (project.getArtifact() != null) {
1417             setArtifact(ArtifactUtils.copyArtifact(project.getArtifact()));
1418         }
1419 
1420         if (project.getManagedVersionMap() != null) {
1421             setManagedVersionMap(project.getManagedVersionMap());
1422         }
1423 
1424         lifecyclePhases.addAll(project.lifecyclePhases);
1425     }
1426 
1427     private static String getProjectReferenceId(String groupId, String artifactId, String version) {
1428         StringBuilder buffer = new StringBuilder(128);
1429         buffer.append(groupId).append(':').append(artifactId).append(':').append(version);
1430         return buffer.toString();
1431     }
1432 
1433     /**
1434      * Sets the value of the context value of this project identified by the given key. If the supplied value is
1435      * <code>null</code>, the context value is removed from this project. Context values are intended to allow core
1436      * extensions to associate derived state with project instances.
1437      */
1438     public void setContextValue(String key, Object value) {
1439         if (context == null) {
1440             context = new HashMap<>();
1441         }
1442         if (value != null) {
1443             context.put(key, value);
1444         } else {
1445             context.remove(key);
1446         }
1447     }
1448 
1449     /**
1450      * Returns context value of this project associated with the given key or null if this project has no such value.
1451      */
1452     public Object getContextValue(String key) {
1453         if (context == null) {
1454             return null;
1455         }
1456         return context.get(key);
1457     }
1458 
1459     /**
1460      * Sets the project's class realm. <strong>Warning:</strong> This is an internal utility method that is only public
1461      * for technical reasons, it is not part of the public API. In particular, this method can be changed or deleted
1462      * without prior notice and must not be used by plugins.
1463      *
1464      * @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
1465      */
1466     public void setClassRealm(ClassRealm classRealm) {
1467         this.classRealm = classRealm;
1468     }
1469 
1470     /**
1471      * Gets the project's class realm. This class realm hosts the build extensions of the project.
1472      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1473      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1474      * used by plugins.
1475      *
1476      * @return The project's class realm or {@code null}.
1477      */
1478     public ClassRealm getClassRealm() {
1479         return classRealm;
1480     }
1481 
1482     /**
1483      * Sets the artifact filter used to exclude shared extension artifacts from plugin realms. <strong>Warning:</strong>
1484      * This is an internal utility method that is only public for technical reasons, it is not part of the public API.
1485      * In particular, this method can be changed or deleted without prior notice and must not be used by plugins.
1486      *
1487      * @param extensionDependencyFilter The dependency filter to apply to plugins, may be {@code null}.
1488      */
1489     public void setExtensionDependencyFilter(DependencyFilter extensionDependencyFilter) {
1490         this.extensionDependencyFilter = extensionDependencyFilter;
1491     }
1492 
1493     /**
1494      * Gets the dependency filter used to exclude shared extension artifacts from plugin realms.
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      * @return The dependency filter or {@code null}.
1500      */
1501     public DependencyFilter getExtensionDependencyFilter() {
1502         return extensionDependencyFilter;
1503     }
1504 
1505     /**
1506      * Sets the transitive dependency artifacts that have been resolved/collected for this project.
1507      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1508      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1509      * used by plugins.
1510      *
1511      * @param artifacts The set of artifacts, may be {@code null}.
1512      */
1513     public void setResolvedArtifacts(Set<Artifact> artifacts) {
1514         this.resolvedArtifacts = (artifacts != null) ? artifacts : Collections.emptySet();
1515         this.artifacts = null;
1516         this.artifactMap = null;
1517     }
1518 
1519     /**
1520      * Sets the scope filter to select the artifacts being exposed to the currently executed mojo.
1521      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1522      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1523      * used by plugins.
1524      *
1525      * @param artifactFilter The artifact filter, may be {@code null} to exclude all artifacts.
1526      */
1527     public void setArtifactFilter(ArtifactFilter artifactFilter) {
1528         this.artifactFilter = artifactFilter;
1529         this.artifacts = null;
1530         this.artifactMap = null;
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 phase The phase to check for, must not be {@code null}.
1539      * @return {@code true} if the phase has been seen.
1540      */
1541     public boolean hasLifecyclePhase(String phase) {
1542         return lifecyclePhases.contains(phase);
1543     }
1544 
1545     /**
1546      * <strong>Warning:</strong> This is an internal utility method that is only public for technical reasons, it is not
1547      * part of the public API. In particular, this method can be changed or deleted without prior notice and must not be
1548      * used by plugins.
1549      *
1550      * @param lifecyclePhase The lifecycle phase to add, must not be {@code null}.
1551      */
1552     public void addLifecyclePhase(String lifecyclePhase) {
1553         lifecyclePhases.add(lifecyclePhase);
1554     }
1555 
1556     // ----------------------------------------------------------------------------------------------------------------
1557     //
1558     //
1559     // D E P R E C A T E D
1560     //
1561     //
1562     // ----------------------------------------------------------------------------------------------------------------
1563     //
1564     // Everything below will be removed for Maven 4.0.0
1565     //
1566     // ----------------------------------------------------------------------------------------------------------------
1567 
1568     private ProjectBuildingRequest projectBuilderConfiguration;
1569 
1570     private Map<String, String> moduleAdjustments;
1571 
1572     @Deprecated // This appears only to be used in test code
1573     public String getModulePathAdjustment(MavenProject moduleProject) throws IOException {
1574         // FIXME: This is hacky. What if module directory doesn't match artifactid, and parent
1575         // is coming from the repository??
1576         String module = moduleProject.getArtifactId();
1577 
1578         File moduleFile = moduleProject.getFile();
1579 
1580         if (moduleFile != null) {
1581             File moduleDir = moduleFile.getCanonicalFile().getParentFile();
1582 
1583             module = moduleDir.getName();
1584         }
1585 
1586         if (moduleAdjustments == null) {
1587             moduleAdjustments = new HashMap<>();
1588 
1589             List<String> modules = getModules();
1590             if (modules != null) {
1591                 for (String modulePath : modules) {
1592                     String moduleName = modulePath;
1593 
1594                     if (moduleName.endsWith("/") || moduleName.endsWith("\\")) {
1595                         moduleName = moduleName.substring(0, moduleName.length() - 1);
1596                     }
1597 
1598                     int lastSlash = moduleName.lastIndexOf('/');
1599 
1600                     if (lastSlash < 0) {
1601                         lastSlash = moduleName.lastIndexOf('\\');
1602                     }
1603 
1604                     String adjustment = null;
1605 
1606                     if (lastSlash > -1) {
1607                         moduleName = moduleName.substring(lastSlash + 1);
1608                         adjustment = modulePath.substring(0, lastSlash);
1609                     }
1610 
1611                     moduleAdjustments.put(moduleName, adjustment);
1612                 }
1613             }
1614         }
1615 
1616         return moduleAdjustments.get(module);
1617     }
1618 
1619     @Deprecated
1620     public Set<Artifact> createArtifacts(ArtifactFactory artifactFactory, String inheritedScope, ArtifactFilter filter)
1621             throws InvalidDependencyVersionException {
1622         return DefaultProjectArtifactFactory.createArtifacts(
1623                 artifactFactory, getModel().getDependencies(), inheritedScope, filter, this);
1624     }
1625 
1626     @Deprecated
1627     protected void setScriptSourceRoots(List<String> scriptSourceRoots) {
1628         setSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT, scriptSourceRoots);
1629     }
1630 
1631     @Deprecated
1632     public void addScriptSourceRoot(String path) {
1633         addSourceRoot(ProjectScope.MAIN, Language.SCRIPT, path);
1634     }
1635 
1636     @Deprecated
1637     public List<String> getScriptSourceRoots() {
1638         return getSourceRootDirs(ProjectScope.MAIN, Language.SCRIPT);
1639     }
1640 
1641     @Deprecated
1642     public List<Artifact> getCompileArtifacts() {
1643         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1644 
1645         for (Artifact a : getArtifacts()) {
1646             // TODO classpath check doesn't belong here - that's the other method
1647             if (a.getArtifactHandler().isAddedToClasspath()) {
1648                 // TODO let the scope handler deal with this
1649                 if (isCompilePathElement(a.getScope())) {
1650                     list.add(a);
1651                 }
1652             }
1653         }
1654         return list;
1655     }
1656 
1657     @Deprecated
1658     public List<Dependency> getCompileDependencies() {
1659         Set<Artifact> artifacts = getArtifacts();
1660 
1661         if ((artifacts == null) || artifacts.isEmpty()) {
1662             return Collections.emptyList();
1663         }
1664 
1665         List<Dependency> list = new ArrayList<>(artifacts.size());
1666 
1667         for (Artifact a : getArtifacts()) {
1668             // TODO let the scope handler deal with this
1669             if (isCompilePathElement(a.getScope())) {
1670                 Dependency dependency = new Dependency();
1671 
1672                 dependency.setArtifactId(a.getArtifactId());
1673                 dependency.setGroupId(a.getGroupId());
1674                 dependency.setVersion(a.getVersion());
1675                 dependency.setScope(a.getScope());
1676                 dependency.setType(a.getType());
1677                 dependency.setClassifier(a.getClassifier());
1678 
1679                 list.add(dependency);
1680             }
1681         }
1682         return Collections.unmodifiableList(list);
1683     }
1684 
1685     @Deprecated
1686     public List<Artifact> getTestArtifacts() {
1687         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1688 
1689         for (Artifact a : getArtifacts()) {
1690             // TODO classpath check doesn't belong here - that's the other method
1691             if (a.getArtifactHandler().isAddedToClasspath()) {
1692                 list.add(a);
1693             }
1694         }
1695         return list;
1696     }
1697 
1698     @Deprecated
1699     public List<Dependency> getTestDependencies() {
1700         Set<Artifact> artifacts = getArtifacts();
1701 
1702         if ((artifacts == null) || artifacts.isEmpty()) {
1703             return Collections.emptyList();
1704         }
1705 
1706         List<Dependency> list = new ArrayList<>(artifacts.size());
1707 
1708         for (Artifact a : getArtifacts()) {
1709             Dependency dependency = new Dependency();
1710 
1711             dependency.setArtifactId(a.getArtifactId());
1712             dependency.setGroupId(a.getGroupId());
1713             dependency.setVersion(a.getVersion());
1714             dependency.setScope(a.getScope());
1715             dependency.setType(a.getType());
1716             dependency.setClassifier(a.getClassifier());
1717 
1718             list.add(dependency);
1719         }
1720         return Collections.unmodifiableList(list);
1721     }
1722 
1723     @Deprecated // used by the Maven ITs
1724     public List<Dependency> getRuntimeDependencies() {
1725         Set<Artifact> artifacts = getArtifacts();
1726 
1727         if ((artifacts == null) || artifacts.isEmpty()) {
1728             return Collections.emptyList();
1729         }
1730 
1731         List<Dependency> list = new ArrayList<>(artifacts.size());
1732 
1733         for (Artifact a : getArtifacts()) {
1734             // TODO let the scope handler deal with this
1735             if (isRuntimePathElement(a.getScope())) {
1736                 Dependency dependency = new Dependency();
1737 
1738                 dependency.setArtifactId(a.getArtifactId());
1739                 dependency.setGroupId(a.getGroupId());
1740                 dependency.setVersion(a.getVersion());
1741                 dependency.setScope(a.getScope());
1742                 dependency.setType(a.getType());
1743                 dependency.setClassifier(a.getClassifier());
1744 
1745                 list.add(dependency);
1746             }
1747         }
1748         return Collections.unmodifiableList(list);
1749     }
1750 
1751     @Deprecated
1752     public List<Artifact> getRuntimeArtifacts() {
1753         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1754 
1755         for (Artifact a : getArtifacts()) {
1756             // TODO classpath check doesn't belong here - that's the other method
1757             if (a.getArtifactHandler().isAddedToClasspath() && isRuntimePathElement(a.getScope())) {
1758                 list.add(a);
1759             }
1760         }
1761         return list;
1762     }
1763 
1764     @Deprecated
1765     public List<String> getSystemClasspathElements() throws DependencyResolutionRequiredException {
1766         List<String> list = new ArrayList<>(getArtifacts().size());
1767 
1768         String d = getBuild().getOutputDirectory();
1769         if (d != null) {
1770             list.add(d);
1771         }
1772 
1773         for (Artifact a : getArtifacts()) {
1774             if (a.getArtifactHandler().isAddedToClasspath()) {
1775                 // TODO let the scope handler deal with this
1776                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1777                     File f = a.getFile();
1778                     if (f != null) {
1779                         list.add(f.getPath());
1780                     }
1781                 }
1782             }
1783         }
1784         return list;
1785     }
1786 
1787     @Deprecated
1788     public List<Artifact> getSystemArtifacts() {
1789         List<Artifact> list = new ArrayList<>(getArtifacts().size());
1790 
1791         for (Artifact a : getArtifacts()) {
1792             // TODO classpath check doesn't belong here - that's the other method
1793             if (a.getArtifactHandler().isAddedToClasspath()) {
1794                 // TODO let the scope handler deal with this
1795                 if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1796                     list.add(a);
1797                 }
1798             }
1799         }
1800         return list;
1801     }
1802 
1803     @Deprecated
1804     public List<Dependency> getSystemDependencies() {
1805         Set<Artifact> artifacts = getArtifacts();
1806 
1807         if ((artifacts == null) || artifacts.isEmpty()) {
1808             return Collections.emptyList();
1809         }
1810 
1811         List<Dependency> list = new ArrayList<>(artifacts.size());
1812 
1813         for (Artifact a : getArtifacts()) {
1814             // TODO let the scope handler deal with this
1815             if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
1816                 Dependency dependency = new Dependency();
1817 
1818                 dependency.setArtifactId(a.getArtifactId());
1819                 dependency.setGroupId(a.getGroupId());
1820                 dependency.setVersion(a.getVersion());
1821                 dependency.setScope(a.getScope());
1822                 dependency.setType(a.getType());
1823                 dependency.setClassifier(a.getClassifier());
1824 
1825                 list.add(dependency);
1826             }
1827         }
1828         return Collections.unmodifiableList(list);
1829     }
1830 
1831     @Deprecated
1832     public void setReporting(Reporting reporting) {
1833         getModel().setReporting(reporting);
1834     }
1835 
1836     @Deprecated
1837     public Reporting getReporting() {
1838         return getModel().getReporting();
1839     }
1840 
1841     @Deprecated
1842     public void setReportArtifacts(Set<Artifact> reportArtifacts) {
1843         this.reportArtifacts = reportArtifacts;
1844 
1845         reportArtifactMap = null;
1846     }
1847 
1848     @Deprecated
1849     public Set<Artifact> getReportArtifacts() {
1850         return reportArtifacts;
1851     }
1852 
1853     @Deprecated
1854     public Map<String, Artifact> getReportArtifactMap() {
1855         if (reportArtifactMap == null) {
1856             reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getReportArtifacts());
1857         }
1858 
1859         return reportArtifactMap;
1860     }
1861 
1862     @Deprecated
1863     public void setExtensionArtifacts(Set<Artifact> extensionArtifacts) {
1864         this.extensionArtifacts = extensionArtifacts;
1865         extensionArtifactMap = null;
1866     }
1867 
1868     @Deprecated
1869     public Set<Artifact> getExtensionArtifacts() {
1870         return extensionArtifacts;
1871     }
1872 
1873     @Deprecated
1874     public Map<String, Artifact> getExtensionArtifactMap() {
1875         if (extensionArtifactMap == null) {
1876             extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getExtensionArtifacts());
1877         }
1878 
1879         return extensionArtifactMap;
1880     }
1881 
1882     @Deprecated
1883     public List<ReportPlugin> getReportPlugins() {
1884         if (getModel().getReporting() == null) {
1885             return Collections.emptyList();
1886         }
1887         return Collections.unmodifiableList(getModel().getReporting().getPlugins());
1888     }
1889 
1890     @Deprecated
1891     public Xpp3Dom getReportConfiguration(String pluginGroupId, String pluginArtifactId, String reportSetId) {
1892         Xpp3Dom dom = null;
1893 
1894         // ----------------------------------------------------------------------
1895         // I would like to be able to look up the Mojo object using a key but
1896         // we have a limitation in modello that will be remedied shortly. So
1897         // for now I have to iterate through and see what we have.
1898         // ----------------------------------------------------------------------
1899 
1900         if (getReportPlugins() != null) {
1901             for (ReportPlugin plugin : getReportPlugins()) {
1902                 if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
1903                     dom = (Xpp3Dom) plugin.getConfiguration();
1904 
1905                     if (reportSetId != null) {
1906                         ReportSet reportSet = plugin.getReportSetsAsMap().get(reportSetId);
1907                         if (reportSet != null) {
1908                             Xpp3Dom executionConfiguration = (Xpp3Dom) reportSet.getConfiguration();
1909                             if (executionConfiguration != null) {
1910                                 Xpp3Dom newDom = new Xpp3Dom(executionConfiguration);
1911                                 dom = Xpp3Dom.mergeXpp3Dom(newDom, dom);
1912                             }
1913                         }
1914                     }
1915                     break;
1916                 }
1917             }
1918         }
1919 
1920         if (dom != null) {
1921             // make a copy so the original in the POM doesn't get messed with
1922             dom = new Xpp3Dom(dom);
1923         }
1924 
1925         return dom;
1926     }
1927 
1928     /**
1929      * @deprecated Use MavenProjectHelper.attachArtifact(..) instead.
1930      */
1931     @Deprecated
1932     public void attachArtifact(String type, String classifier, File file) {}
1933 
1934     /**
1935      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1936      */
1937     @Deprecated
1938     public void writeModel(Writer writer) throws IOException {
1939         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1940         pomWriter.write(writer, getModel());
1941     }
1942 
1943     /**
1944      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
1945      */
1946     @Deprecated
1947     public void writeOriginalModel(Writer writer) throws IOException {
1948         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
1949         pomWriter.write(writer, getOriginalModel());
1950     }
1951 
1952     @Deprecated
1953     public Artifact replaceWithActiveArtifact(Artifact pluginArtifact) {
1954         return pluginArtifact;
1955     }
1956 
1957     /**
1958      * Gets 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      * @return The project building request or {@code null}.
1962      * @since 2.1
1963      */
1964     @Deprecated
1965     public ProjectBuildingRequest getProjectBuildingRequest() {
1966         return projectBuilderConfiguration;
1967     }
1968 
1969     /**
1970      * Sets the project building request from which this project instance was created. <strong>Warning:</strong> This is
1971      * a utility method that is meant to assist integrators of Maven, it must not be used by Maven plugins.
1972      *
1973      * @param projectBuildingRequest The project building request, may be {@code null}.
1974      * @since 2.1
1975      */
1976     // used by maven-dependency-tree
1977     @Deprecated
1978     public void setProjectBuildingRequest(ProjectBuildingRequest projectBuildingRequest) {
1979         this.projectBuilderConfiguration = projectBuildingRequest;
1980     }
1981 
1982     /**
1983      * @since 4.0.0
1984      * @return the rootDirectory for this project
1985      * @throws IllegalStateException if the rootDirectory cannot be found
1986      */
1987     public Path getRootDirectory() {
1988         if (rootDirectory == null) {
1989             throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
1990         }
1991         return rootDirectory;
1992     }
1993 
1994     public void setRootDirectory(Path rootDirectory) {
1995         this.rootDirectory = rootDirectory;
1996     }
1997 }