1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.nio.charset.StandardCharsets;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.util.AbstractMap;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.LinkedHashSet;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Properties;
42 import java.util.Set;
43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.function.Function;
45 import java.util.function.Supplier;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
48
49 import org.apache.maven.RepositoryUtils;
50 import org.apache.maven.api.ArtifactCoordinates;
51 import org.apache.maven.api.Language;
52 import org.apache.maven.api.LocalRepository;
53 import org.apache.maven.api.ProjectScope;
54 import org.apache.maven.api.SessionData;
55 import org.apache.maven.api.annotations.Nonnull;
56 import org.apache.maven.api.annotations.Nullable;
57 import org.apache.maven.api.model.Build;
58 import org.apache.maven.api.model.Dependency;
59 import org.apache.maven.api.model.DependencyManagement;
60 import org.apache.maven.api.model.DeploymentRepository;
61 import org.apache.maven.api.model.Extension;
62 import org.apache.maven.api.model.Model;
63 import org.apache.maven.api.model.Plugin;
64 import org.apache.maven.api.model.Profile;
65 import org.apache.maven.api.model.ReportPlugin;
66 import org.apache.maven.api.services.ArtifactResolver;
67 import org.apache.maven.api.services.ArtifactResolverException;
68 import org.apache.maven.api.services.ArtifactResolverRequest;
69 import org.apache.maven.api.services.ArtifactResolverResult;
70 import org.apache.maven.api.services.BuilderProblem.Severity;
71 import org.apache.maven.api.services.ModelBuilder;
72 import org.apache.maven.api.services.ModelBuilderException;
73 import org.apache.maven.api.services.ModelBuilderRequest;
74 import org.apache.maven.api.services.ModelBuilderResult;
75 import org.apache.maven.api.services.ModelProblem;
76 import org.apache.maven.api.services.ModelProblem.Version;
77 import org.apache.maven.api.services.ModelProblemCollector;
78 import org.apache.maven.api.services.ModelSource;
79 import org.apache.maven.api.services.ModelTransformer;
80 import org.apache.maven.api.services.ProblemCollector;
81 import org.apache.maven.api.services.Source;
82 import org.apache.maven.api.services.Sources;
83 import org.apache.maven.api.services.model.LifecycleBindingsInjector;
84 import org.apache.maven.artifact.Artifact;
85 import org.apache.maven.artifact.InvalidRepositoryException;
86 import org.apache.maven.artifact.repository.ArtifactRepository;
87 import org.apache.maven.bridge.MavenRepositorySystem;
88 import org.apache.maven.impl.DefaultSourceRoot;
89 import org.apache.maven.impl.InternalSession;
90 import org.apache.maven.impl.resolver.ArtifactDescriptorUtils;
91 import org.apache.maven.internal.impl.InternalMavenSession;
92 import org.apache.maven.model.building.DefaultModelProblem;
93 import org.apache.maven.model.building.FileModelSource;
94 import org.apache.maven.model.building.ModelBuildingRequest;
95 import org.apache.maven.model.building.ModelSource2;
96 import org.apache.maven.model.root.RootLocator;
97 import org.apache.maven.plugin.PluginManagerException;
98 import org.apache.maven.plugin.PluginResolutionException;
99 import org.apache.maven.plugin.version.PluginVersionResolutionException;
100 import org.eclipse.aether.RepositorySystem;
101 import org.eclipse.aether.RepositorySystemSession;
102 import org.eclipse.aether.repository.LocalRepositoryManager;
103 import org.slf4j.Logger;
104 import org.slf4j.LoggerFactory;
105
106
107
108
109 @Named
110 @Singleton
111 public class DefaultProjectBuilder implements ProjectBuilder {
112
113 private final Logger logger = LoggerFactory.getLogger(getClass());
114 private final ModelBuilder modelBuilder;
115 private final ProjectBuildingHelper projectBuildingHelper;
116 private final MavenRepositorySystem repositorySystem;
117 private final ProjectDependenciesResolver dependencyResolver;
118 private final RootLocator rootLocator;
119 private final LifecycleBindingsInjector lifecycleBindingsInjector;
120
121 @SuppressWarnings("checkstyle:ParameterNumber")
122 @Inject
123 public DefaultProjectBuilder(
124 ModelBuilder modelBuilder,
125 ProjectBuildingHelper projectBuildingHelper,
126 MavenRepositorySystem repositorySystem,
127 RepositorySystem repoSystem,
128 ProjectDependenciesResolver dependencyResolver,
129 RootLocator rootLocator,
130 LifecycleBindingsInjector lifecycleBindingsInjector) {
131 this.modelBuilder = modelBuilder;
132 this.projectBuildingHelper = projectBuildingHelper;
133 this.repositorySystem = repositorySystem;
134 this.dependencyResolver = dependencyResolver;
135 this.rootLocator = rootLocator;
136 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
137 }
138
139
140
141
142 @Override
143 public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) throws ProjectBuildingException {
144 try (BuildSession bs = new BuildSession(request)) {
145 Path path = pomFile.toPath();
146 return bs.build(false, path, Sources.buildSource(path));
147 }
148 }
149
150 @Deprecated
151 @Override
152 public ProjectBuildingResult build(
153 org.apache.maven.model.building.ModelSource modelSource, ProjectBuildingRequest request)
154 throws ProjectBuildingException {
155 return build(toSource(modelSource), request);
156 }
157
158 @Deprecated
159 static ModelSource toSource(org.apache.maven.model.building.ModelSource modelSource) {
160 if (modelSource instanceof FileModelSource fms) {
161 return Sources.buildSource(fms.getPath());
162 } else {
163 return new WrapModelSource(modelSource);
164 }
165 }
166
167 @Override
168 public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
169 throws ProjectBuildingException {
170 try (BuildSession bs = new BuildSession(request)) {
171 return bs.build(false, null, modelSource);
172 }
173 }
174
175 @Override
176 public ProjectBuildingResult build(Artifact artifact, ProjectBuildingRequest request)
177 throws ProjectBuildingException {
178 return build(artifact, false, request);
179 }
180
181 @Override
182 public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request)
183 throws ProjectBuildingException {
184 try (BuildSession bs = new BuildSession(request)) {
185 return bs.build(false, artifact, allowStubModel, request.getRemoteRepositories());
186 }
187 }
188
189 @Override
190 public List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive, ProjectBuildingRequest request)
191 throws ProjectBuildingException {
192 try (BuildSession bs = new BuildSession(request)) {
193 return bs.build(pomFiles, recursive);
194 }
195 }
196
197 private static class StubModelSource implements ModelSource {
198 private final String xml;
199 private final Artifact artifact;
200
201 StubModelSource(String xml, Artifact artifact) {
202 this.xml = xml;
203 this.artifact = artifact;
204 }
205
206 @Override
207 @Nullable
208 public ModelSource resolve(@Nonnull ModelLocator modelLocator, @Nonnull String relative) {
209 return null;
210 }
211
212 @Override
213 @Nullable
214 public Path getPath() {
215 return null;
216 }
217
218 @Override
219 @Nonnull
220 public InputStream openStream() throws IOException {
221 return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
222 }
223
224 @Override
225 @Nonnull
226 public String getLocation() {
227 return artifact.getId();
228 }
229
230 @Override
231 @Nullable
232 public Source resolve(@Nonnull String relative) {
233 return null;
234 }
235
236 @Override
237 public boolean equals(Object o) {
238 if (this == o) {
239 return true;
240 }
241 if (o == null || getClass() != o.getClass()) {
242 return false;
243 }
244 StubModelSource that = (StubModelSource) o;
245 return Objects.equals(xml, that.xml) && Objects.equals(artifact, that.artifact);
246 }
247
248 @Override
249 public int hashCode() {
250 return Objects.hash(xml, artifact);
251 }
252 }
253
254 private static class WrapModelSource implements ModelSource {
255 private final org.apache.maven.model.building.ModelSource modelSource;
256
257 WrapModelSource(org.apache.maven.model.building.ModelSource modelSource) {
258 this.modelSource = modelSource;
259 }
260
261 @Override
262 @Nullable
263 public ModelSource resolve(@Nonnull ModelLocator modelLocator, @Nonnull String relative) {
264 return null;
265 }
266
267 @Override
268 @Nullable
269 public Path getPath() {
270 return null;
271 }
272
273 @Override
274 @Nonnull
275 public InputStream openStream() throws IOException {
276 return modelSource.getInputStream();
277 }
278
279 @Override
280 @Nonnull
281 public String getLocation() {
282 return modelSource.getLocation();
283 }
284
285 @Override
286 @Nullable
287 public Source resolve(@Nonnull String relative) {
288 if (modelSource instanceof ModelSource2 ms) {
289 return toSource(ms.getRelatedSource(relative));
290 } else {
291 return null;
292 }
293 }
294
295 @Override
296 public boolean equals(Object o) {
297 if (this == o) {
298 return true;
299 }
300 if (o == null || getClass() != o.getClass()) {
301 return false;
302 }
303 WrapModelSource that = (WrapModelSource) o;
304 return Objects.equals(modelSource, that.modelSource);
305 }
306
307 @Override
308 public int hashCode() {
309 return Objects.hashCode(modelSource);
310 }
311 }
312
313 class BuildSession implements AutoCloseable {
314 private final ProjectBuildingRequest request;
315 private final InternalSession session;
316 private final ModelBuilder.ModelBuilderSession modelBuilderSession;
317 private final Map<String, MavenProject> projectIndex = new ConcurrentHashMap<>(256);
318
319
320 private final Map<String, List<ArtifactRepository>> projectRepositories = new ConcurrentHashMap<>();
321
322
323
324
325
326 private List<ArtifactRepository> getEffectiveRepositories(String projectId) {
327 List<ArtifactRepository> stored = projectRepositories.get(projectId);
328 return stored != null ? stored : request.getRemoteRepositories();
329 }
330
331 BuildSession(ProjectBuildingRequest request) {
332 this.request = request;
333 InternalSession session = InternalSession.from(request.getRepositorySession());
334 Path basedir = request.getLocalRepository() != null
335 ? request.getLocalRepository().getBasedirPath()
336 : null;
337 if (basedir != null) {
338 LocalRepository localRepository = session.createLocalRepository(basedir);
339 session = InternalSession.from(session.withLocalRepository(localRepository));
340 }
341 this.session = session;
342 this.modelBuilderSession = modelBuilder.newSession();
343
344
345
346
347 this.session
348 .getData()
349 .replace(SessionData.key(ModelBuilder.ModelBuilderSession.class), null, modelBuilderSession);
350 }
351
352 @Override
353 public void close() {}
354
355 ProjectBuildingResult build(boolean parent, Path pomFile, ModelSource modelSource)
356 throws ProjectBuildingException {
357 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
358
359 try {
360 MavenProject project = request.getProject();
361
362 ProblemCollector<ModelProblem> problemCollector = null;
363 Throwable error = null;
364
365 if (project == null) {
366 project = new MavenProject();
367 project.setFile(pomFile != null ? pomFile.toFile() : null);
368
369 boolean reactorMember = pomFile != null
370 && session.getProjects() != null
371 && session.getProjects().stream()
372 .anyMatch(
373 p -> p.getPomPath().toAbsolutePath().equals(pomFile.toAbsolutePath()));
374 boolean isStandalone = pomFile == null
375 && modelSource != null
376 && modelSource.getLocation().startsWith("jar:")
377 && modelSource.getLocation().endsWith("/org/apache/maven/project/standalone.xml");
378
379 ModelBuilderRequest.ModelBuilderRequestBuilder builder = getModelBuildingRequest();
380 ModelBuilderRequest.RequestType type = reactorMember
381 || isStandalone
382 || (pomFile != null
383 && this.request.isProcessPlugins()
384 && this.request.getValidationLevel()
385 == ModelBuildingRequest.VALIDATION_LEVEL_STRICT)
386 ? ModelBuilderRequest.RequestType.BUILD_EFFECTIVE
387 : (parent
388 ? ModelBuilderRequest.RequestType.CONSUMER_PARENT
389 : ModelBuilderRequest.RequestType.CONSUMER_DEPENDENCY);
390 MavenProject theProject = project;
391 ModelBuilderRequest request = builder.source(modelSource)
392 .requestType(type)
393 .locationTracking(true)
394 .lifecycleBindingsInjector(
395 (m, r, p) -> injectLifecycleBindings(m, r, p, theProject, this.request))
396 .build();
397
398 if (pomFile != null) {
399 project.setRootDirectory(rootLocator.findRoot(pomFile.getParent()));
400 }
401
402 ModelBuilderResult result;
403 try {
404 result = modelBuilderSession.build(request);
405 } catch (ModelBuilderException e) {
406 result = e.getResult();
407 if (result == null || result.getEffectiveModel() == null) {
408 throw new ProjectBuildingException(
409 e.getModelId(), e.getMessage(), pomFile != null ? pomFile.toFile() : null, e);
410 }
411
412 error = e;
413 }
414
415 problemCollector = result.getProblemCollector();
416
417 initProject(project, result);
418 }
419
420 DependencyResolutionResult resolutionResult = null;
421
422 if (request.isResolveDependencies()) {
423 projectBuildingHelper.selectProjectRealm(project);
424 resolutionResult = resolveDependencies(project);
425 }
426
427 ProjectBuildingResult result =
428 new DefaultProjectBuildingResult(project, convert(problemCollector), resolutionResult);
429
430 if (error != null) {
431 ProjectBuildingException e = new ProjectBuildingException(List.of(result));
432 e.initCause(error);
433 throw e;
434 }
435
436 return result;
437 } finally {
438 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
439 }
440 }
441
442 private boolean isProjectPom(Path pomFile) {
443 List<org.apache.maven.api.Project> projects = session.getProjects();
444 if (pomFile == null || projects == null) {
445 return false;
446 }
447 Path path = pomFile.toAbsolutePath().normalize();
448 return projects.stream()
449 .filter(Objects::nonNull)
450 .anyMatch(p -> p.getPomPath().toAbsolutePath().normalize().equals(path));
451 }
452
453 ProjectBuildingResult build(
454 boolean parent, Artifact artifact, boolean allowStubModel, List<ArtifactRepository> repositories)
455 throws ProjectBuildingException {
456 org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
457 pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
458
459 boolean localProject;
460
461 try {
462 ArtifactCoordinates coordinates = session.createArtifactCoordinates(session.getArtifact(pomArtifact));
463
464 ArtifactResolverRequest req = ArtifactResolverRequest.builder()
465 .session(session)
466 .repositories(repositories.stream()
467 .map(RepositoryUtils::toRepo)
468 .map(session::getRemoteRepository)
469 .toList())
470 .coordinates(List.of(coordinates))
471 .build();
472 ArtifactResolverResult res =
473 session.getService(ArtifactResolver.class).resolve(req);
474 ArtifactResolverResult.ResultItem resItem = res.getResult(coordinates);
475
476 pomArtifact = InternalMavenSession.from(session).toArtifact(resItem.getArtifact());
477
478
479 localProject = resItem.getRepository() instanceof org.apache.maven.api.WorkspaceRepository
480 && isProjectPom(pomArtifact.getPath());
481 } catch (ArtifactResolverException e) {
482 if (e.getResult().getResults().values().iterator().next().isMissing() && allowStubModel) {
483 return build(parent, null, createStubModelSource(artifact));
484 }
485 throw new ProjectBuildingException(
486 artifact.getId(), "Error resolving project artifact: " + e.getMessage(), e);
487 }
488
489 Path pomFile = pomArtifact.getPath();
490
491 if (!artifact.isResolved() && "pom".equals(artifact.getType())) {
492 artifact.selectVersion(pomArtifact.getVersion());
493 artifact.setFile(pomFile.toFile());
494 artifact.setResolved(true);
495 }
496
497 if (localProject) {
498 return build(parent, pomFile, Sources.buildSource(pomFile));
499 } else {
500 return build(
501 parent,
502 null,
503 Sources.resolvedSource(
504 pomFile,
505 artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()));
506 }
507 }
508
509 List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive) throws ProjectBuildingException {
510 List<ProjectBuildingResult> results = doBuild(pomFiles, recursive);
511 if (results.stream()
512 .flatMap(r -> r.getProblems().stream())
513 .anyMatch(p -> p.getSeverity() != org.apache.maven.model.building.ModelProblem.Severity.WARNING)) {
514 org.apache.maven.model.building.ModelProblem cycle = results.stream()
515 .flatMap(r -> r.getProblems().stream())
516 .filter(p -> p.getException() instanceof CycleDetectedException)
517 .findAny()
518 .orElse(null);
519 if (cycle != null) {
520 final CycleDetectedException cde = (CycleDetectedException) cycle.getException();
521 throw new ProjectBuildingException(
522 null,
523 "The projects in the reactor contain a cyclic reference: " + cycle.getMessage(),
524 null,
525 cde);
526 }
527
528 throw new ProjectBuildingException(results);
529 }
530
531 return results;
532 }
533
534 List<ProjectBuildingResult> doBuild(List<File> pomFiles, boolean recursive) {
535 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
536 try {
537 return pomFiles.stream()
538 .map(pomFile -> build(pomFile, recursive))
539 .flatMap(List::stream)
540 .toList();
541 } finally {
542 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
543 }
544 }
545
546 @SuppressWarnings("checkstyle:parameternumber")
547 private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
548 ModelBuilderResult result;
549 try {
550 ModelTransformer injector = (m, r, p) -> {
551 MavenProject project = projectIndex.computeIfAbsent(m.getId(), f -> new MavenProject());
552 return injectLifecycleBindings(m, r, p, project, request);
553 };
554 ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest()
555 .source(Sources.buildSource(pomFile.toPath()))
556 .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT)
557 .locationTracking(true)
558 .recursive(recursive)
559 .lifecycleBindingsInjector(injector)
560 .build();
561 result = modelBuilderSession.build(modelBuildingRequest);
562 } catch (ModelBuilderException e) {
563 result = e.getResult();
564 if (result == null || result.getEffectiveModel() == null) {
565 return List.of(new DefaultProjectBuildingResult(
566 e.getModelId(), pomFile, convert(e.getProblemCollector())));
567 }
568 }
569
570 List<ProjectBuildingResult> results = new ArrayList<>();
571 List<ModelBuilderResult> allModels = results(result).toList();
572 for (ModelBuilderResult r : allModels) {
573 if (r.getEffectiveModel() != null) {
574 File pom = r.getSource().getPath().toFile();
575 MavenProject project =
576 projectIndex.get(r.getEffectiveModel().getId());
577 project.setRootDirectory(
578 rootLocator.findRoot(pom.getParentFile().toPath()));
579 project.setFile(pom);
580 project.setExecutionRoot(pom.equals(pomFile));
581 initProject(project, r);
582 project.setCollectedProjects(results(r)
583 .filter(cr -> cr != r && cr.getEffectiveModel() != null)
584 .map(cr -> projectIndex.get(cr.getEffectiveModel().getId()))
585 .toList());
586
587 DependencyResolutionResult resolutionResult = null;
588 if (request.isResolveDependencies()) {
589 resolutionResult = resolveDependencies(project);
590 }
591 results.add(new DefaultProjectBuildingResult(
592 project, convert(r.getProblemCollector()), resolutionResult));
593 } else {
594
595 String projectId = extractProjectId(r);
596 File sourcePomFile = r.getSource() != null && r.getSource().getPath() != null
597 ? r.getSource().getPath().toFile()
598 : null;
599 results.add(new DefaultProjectBuildingResult(
600 projectId, sourcePomFile, convert(r.getProblemCollector())));
601 }
602 }
603 return results;
604 }
605
606 private Stream<ModelBuilderResult> results(ModelBuilderResult result) {
607 return Stream.concat(result.getChildren().stream().flatMap(this::results), Stream.of(result));
608 }
609
610 private List<org.apache.maven.model.building.ModelProblem> convert(
611 ProblemCollector<ModelProblem> problemCollector) {
612 if (problemCollector == null) {
613 return null;
614 }
615 ArrayList<org.apache.maven.model.building.ModelProblem> problems = new ArrayList<>();
616 problemCollector.problems().map(BuildSession::convert).forEach(problems::add);
617 if (problemCollector.problemsOverflow()) {
618 problems.add(
619 0,
620 new DefaultModelProblem(
621 "Too many model problems reported (listed problems are just a subset of reported problems)",
622 org.apache.maven.model.building.ModelProblem.Severity.WARNING,
623 null,
624 null,
625 -1,
626 -1,
627 null,
628 null));
629 return new ArrayList<>(problems) {
630 @Override
631 public int size() {
632 return problemCollector.totalProblemsReported();
633 }
634 };
635 } else {
636 return problems;
637 }
638 }
639
640 private static org.apache.maven.model.building.ModelProblem convert(ModelProblem p) {
641 return new DefaultModelProblem(
642 p.getMessage(),
643 org.apache.maven.model.building.ModelProblem.Severity.valueOf(
644 p.getSeverity().name()),
645 org.apache.maven.model.building.ModelProblem.Version.valueOf(
646 p.getVersion().name()),
647 p.getSource(),
648 p.getLineNumber(),
649 p.getColumnNumber(),
650 p.getModelId(),
651 p.getException());
652 }
653
654 @SuppressWarnings({"checkstyle:methodlength", "deprecation"})
655 private void initProject(MavenProject project, ModelBuilderResult result) {
656 project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel()));
657 project.setOriginalModel(new org.apache.maven.model.Model(result.getFileModel()));
658
659 initParent(project, result);
660
661 Artifact projectArtifact = repositorySystem.createArtifact(
662 project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging());
663 project.setArtifact(projectArtifact);
664
665
666 if (project.getFile() != null) {
667 Build build = project.getBuild().getDelegate();
668 Path baseDir = project.getBaseDirectory();
669 Function<ProjectScope, String> outputDirectory = (scope) -> {
670 if (scope == ProjectScope.MAIN) {
671 return build.getOutputDirectory();
672 } else if (scope == ProjectScope.TEST) {
673 return build.getTestOutputDirectory();
674 } else {
675 return build.getDirectory();
676 }
677 };
678
679 final SourceHandlingContext sourceContext = new SourceHandlingContext(project, result);
680
681
682 for (org.apache.maven.api.model.Source source : sourceContext.sources) {
683 var sourceRoot = DefaultSourceRoot.fromModel(session, baseDir, outputDirectory, source);
684
685
686 if (sourceContext.shouldAddSource(sourceRoot)) {
687 project.addSourceRoot(sourceRoot);
688 }
689 }
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711 if (sourceContext.sources.isEmpty()) {
712
713 project.addScriptSourceRoot(build.getScriptSourceDirectory());
714 project.addCompileSourceRoot(build.getSourceDirectory());
715 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
716
717 sourceContext.handleResourceConfiguration(ProjectScope.MAIN);
718 sourceContext.handleResourceConfiguration(ProjectScope.TEST);
719 } else {
720
721 if (!sourceContext.hasSources(Language.SCRIPT, ProjectScope.MAIN)) {
722 project.addScriptSourceRoot(build.getScriptSourceDirectory());
723 }
724 if (sourceContext.usesModuleSourceHierarchy()) {
725
726 failIfLegacyDirectoryPresent(
727 build.getSourceDirectory(),
728 baseDir.resolve("src/main/java"),
729 "<sourceDirectory>",
730 project.getId(),
731 result,
732 true);
733 failIfLegacyDirectoryPresent(
734 build.getTestSourceDirectory(),
735 baseDir.resolve("src/test/java"),
736 "<testSourceDirectory>",
737 project.getId(),
738 result,
739 true);
740 } else {
741
742 Path mainDefault = baseDir.resolve("src/main/java");
743 Path testDefault = baseDir.resolve("src/test/java");
744
745 failIfLegacyDirectoryPresent(
746 build.getSourceDirectory(),
747 mainDefault,
748 "<sourceDirectory>",
749 project.getId(),
750 result,
751 false);
752 failIfLegacyDirectoryPresent(
753 build.getTestSourceDirectory(),
754 testDefault,
755 "<testSourceDirectory>",
756 project.getId(),
757 result,
758 false);
759
760
761
762
763 if (!sourceContext.hasSources(Language.JAVA_FAMILY, ProjectScope.MAIN)) {
764 Path configuredMain = Path.of(build.getSourceDirectory())
765 .toAbsolutePath()
766 .normalize();
767 if (configuredMain.equals(
768 mainDefault.toAbsolutePath().normalize())) {
769 project.addCompileSourceRoot(build.getSourceDirectory());
770 }
771 }
772 if (!sourceContext.hasSources(Language.JAVA_FAMILY, ProjectScope.TEST)) {
773 Path configuredTest = Path.of(build.getTestSourceDirectory())
774 .toAbsolutePath()
775 .normalize();
776 if (configuredTest.equals(
777 testDefault.toAbsolutePath().normalize())) {
778 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
779 }
780 }
781 }
782
783
784 sourceContext.failIfMixedModularAndClassicSources();
785
786
787 sourceContext.handleResourceConfiguration(ProjectScope.MAIN);
788 sourceContext.handleResourceConfiguration(ProjectScope.TEST);
789 }
790
791
792
793
794 if (sourceContext.hasSources(Language.RESOURCES, ProjectScope.MAIN)
795 || sourceContext.hasSources(Language.RESOURCES, ProjectScope.TEST)) {
796 project.syncBuildResources();
797 }
798 }
799
800 project.setActiveProfiles(
801 Stream.concat(result.getActivePomProfiles().stream(), result.getActiveExternalProfiles().stream())
802 .map(org.apache.maven.model.Profile::new)
803 .toList());
804
805 project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
806
807
808 Map<String, List<org.apache.maven.api.model.Profile>> profilesByModel =
809 result.getActivePomProfilesByModel();
810
811 if (profilesByModel.isEmpty()) {
812
813
814 project.setInjectedProfileIds(
815 getModelDataId(result.getEffectiveModel()), getProfileIds(result.getActivePomProfiles()));
816 } else {
817 for (Map.Entry<String, List<org.apache.maven.api.model.Profile>> entry : profilesByModel.entrySet()) {
818 project.setInjectedProfileIds(entry.getKey(), getProfileIds(entry.getValue()));
819 }
820 }
821
822
823
824
825
826 project.setProjectBuildingRequest(request);
827
828
829 Set<Artifact> pluginArtifacts = new HashSet<>();
830 for (Plugin plugin : project.getModel().getDelegate().getBuild().getPlugins()) {
831 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(plugin));
832
833 if (artifact != null) {
834 pluginArtifacts.add(artifact);
835 }
836 }
837 project.setPluginArtifacts(pluginArtifacts);
838
839
840 Set<Artifact> reportArtifacts = new HashSet<>();
841 for (ReportPlugin report :
842 project.getModel().getDelegate().getReporting().getPlugins()) {
843 Plugin pp = Plugin.newBuilder()
844 .groupId(report.getGroupId())
845 .artifactId(report.getArtifactId())
846 .version(report.getVersion())
847 .build();
848
849 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(pp));
850
851 if (artifact != null) {
852 reportArtifacts.add(artifact);
853 }
854 }
855 project.setReportArtifacts(reportArtifacts);
856
857
858 Set<Artifact> extensionArtifacts = new HashSet<>();
859 List<Extension> extensions =
860 project.getModel().getDelegate().getBuild().getExtensions();
861 if (extensions != null) {
862 for (Extension ext : extensions) {
863 String version;
864 if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
865 version = "RELEASE";
866 } else {
867 version = ext.getVersion();
868 }
869
870 Artifact artifact = repositorySystem.createArtifact(
871 ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
872
873 if (artifact != null) {
874 extensionArtifacts.add(artifact);
875 }
876 }
877 }
878 project.setExtensionArtifacts(extensionArtifacts);
879
880
881 Map<String, Artifact> map = Collections.emptyMap();
882 final DependencyManagement dependencyManagement =
883 project.getModel().getDelegate().getDependencyManagement();
884 if (dependencyManagement != null
885 && dependencyManagement.getDependencies() != null
886 && !dependencyManagement.getDependencies().isEmpty()) {
887 map = new LazyMap<>(() -> {
888 Map<String, Artifact> tmp = new HashMap<>();
889 for (Dependency d : dependencyManagement.getDependencies()) {
890 Artifact artifact =
891 repositorySystem.createDependencyArtifact(new org.apache.maven.model.Dependency(d));
892 if (artifact != null) {
893 tmp.put(d.getManagementKey(), artifact);
894 }
895 }
896 return Collections.unmodifiableMap(tmp);
897 });
898 }
899 project.setManagedVersionMap(map);
900
901
902 if (project.getDistributionManagement() != null
903 && project.getDistributionManagement().getRepository() != null) {
904 try {
905 DeploymentRepository r = project.getModel()
906 .getDelegate()
907 .getDistributionManagement()
908 .getRepository();
909 if (r.getId() != null
910 && !r.getId().isEmpty()
911 && r.getUrl() != null
912 && !r.getUrl().isEmpty()) {
913 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
914 new org.apache.maven.model.DeploymentRepository(r));
915 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
916 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
917 project.setReleaseArtifactRepository(repo);
918 }
919 } catch (InvalidRepositoryException e) {
920 throw new IllegalStateException(
921 "Failed to create release distribution repository for " + project.getId(), e);
922 }
923 }
924
925
926 if (project.getDistributionManagement() != null
927 && project.getDistributionManagement().getSnapshotRepository() != null) {
928 try {
929 DeploymentRepository r = project.getModel()
930 .getDelegate()
931 .getDistributionManagement()
932 .getSnapshotRepository();
933 if (r.getId() != null
934 && !r.getId().isEmpty()
935 && r.getUrl() != null
936 && !r.getUrl().isEmpty()) {
937 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
938 new org.apache.maven.model.DeploymentRepository(r));
939 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
940 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
941 project.setSnapshotArtifactRepository(repo);
942 }
943 } catch (InvalidRepositoryException e) {
944 throw new IllegalStateException(
945 "Failed to create snapshot distribution repository for " + project.getId(), e);
946 }
947 }
948
949
950 List<ArtifactRepository> remoteRepositories = request.getRemoteRepositories();
951 try {
952 remoteRepositories = projectBuildingHelper.createArtifactRepositories(
953 project.getModel().getRepositories(), remoteRepositories, request);
954 } catch (Exception e) {
955 result.getProblemCollector()
956 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
957 "",
958 Severity.ERROR,
959 Version.BASE,
960 project.getModel().getDelegate(),
961 -1,
962 -1,
963 e));
964 }
965 project.setRemoteArtifactRepositories(remoteRepositories);
966 }
967
968
969
970
971 private static String getModelDataId(Model model) {
972 return ((model.getGroupId() == null) ? "[inherited]" : model.getGroupId()) + ":"
973 + model.getArtifactId()
974 + ":"
975 + ((model.getVersion() == null) ? "[inherited]" : model.getVersion());
976 }
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002 private void failIfLegacyDirectoryPresent(
1003 String configuredDir,
1004 Path defaultDir,
1005 String elementName,
1006 String projectId,
1007 ModelBuilderResult result,
1008 boolean checkPhysicalPresence) {
1009 if (configuredDir != null) {
1010 Path configuredPath = Path.of(configuredDir).toAbsolutePath().normalize();
1011 Path defaultPath = defaultDir.toAbsolutePath().normalize();
1012 if (!configuredPath.equals(defaultPath)) {
1013
1014 String message = String.format(
1015 "Legacy %s cannot be used in project %s because sources are configured via <sources>. "
1016 + "Remove the %s configuration.",
1017 elementName, projectId, elementName);
1018 logger.error(message);
1019 result.getProblemCollector()
1020 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
1021 message, Severity.ERROR, Version.V41, null, -1, -1, null));
1022 } else if (checkPhysicalPresence && Files.isDirectory(defaultPath)) {
1023
1024 String message = String.format(
1025 "Legacy directory '%s' exists but cannot be used in project %s "
1026 + "because sources are configured via <sources>. "
1027 + "Remove or rename the directory.",
1028 defaultPath, projectId);
1029 logger.error(message);
1030 result.getProblemCollector()
1031 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
1032 message, Severity.ERROR, Version.V41, null, -1, -1, null));
1033 }
1034 }
1035 }
1036
1037 private void initParent(MavenProject project, ModelBuilderResult result) {
1038 Model parentModel = result.getParentModel();
1039
1040 if (parentModel != null) {
1041 final String parentGroupId = getGroupId(parentModel);
1042 final String parentVersion = getVersion(parentModel);
1043
1044 project.setParentArtifact(repositorySystem.createProjectArtifact(
1045 parentGroupId, parentModel.getArtifactId(), parentVersion));
1046
1047 MavenProject parent = projectIndex.get(parentModel.getId());
1048 if (parent == null) {
1049
1050
1051
1052
1053
1054
1055
1056 List<ArtifactRepository> mergedRepositories;
1057 switch (request.getRepositoryMerging()) {
1058 case POM_DOMINANT -> {
1059 LinkedHashSet<ArtifactRepository> reposes =
1060 new LinkedHashSet<>(project.getRemoteArtifactRepositories());
1061 reposes.addAll(request.getRemoteRepositories());
1062 mergedRepositories = List.copyOf(reposes);
1063 }
1064 case REQUEST_DOMINANT -> {
1065 LinkedHashSet<ArtifactRepository> reposes =
1066 new LinkedHashSet<>(request.getRemoteRepositories());
1067 reposes.addAll(project.getRemoteArtifactRepositories());
1068 mergedRepositories = List.copyOf(reposes);
1069 }
1070 default ->
1071 throw new IllegalArgumentException(
1072 "Unsupported repository merging: " + request.getRepositoryMerging());
1073 }
1074
1075
1076
1077 projectRepositories.put(project.getId(), mergedRepositories);
1078
1079 Path parentPomFile = parentModel.getPomFile();
1080 if (parentPomFile != null) {
1081 project.setParentFile(parentPomFile.toFile());
1082 try {
1083 parent = build(true, parentPomFile, Sources.buildSource(parentPomFile))
1084 .getProject();
1085 } catch (ProjectBuildingException e) {
1086
1087 if (logger.isDebugEnabled()) {
1088
1089 logger.warn("Failed to build parent project for " + project.getId(), e);
1090 } else {
1091
1092 logger.warn("Failed to build parent project for " + project.getId());
1093 }
1094 }
1095 } else {
1096 Artifact parentArtifact = project.getParentArtifact();
1097 try {
1098 parent = build(true, parentArtifact, false, getEffectiveRepositories(project.getId()))
1099 .getProject();
1100 } catch (ProjectBuildingException e) {
1101
1102 if (logger.isDebugEnabled()) {
1103
1104 logger.warn("Failed to build parent project for " + project.getId(), e);
1105 } else {
1106
1107 logger.warn("Failed to build parent project for " + project.getId());
1108 }
1109 }
1110 }
1111 }
1112 project.setParent(parent);
1113 if (project.getParentFile() == null && parent != null) {
1114 project.setParentFile(parent.getFile());
1115 }
1116 }
1117 }
1118
1119 private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() {
1120 ModelBuilderRequest.ModelBuilderRequestBuilder modelBuildingRequest = ModelBuilderRequest.builder();
1121
1122 modelBuildingRequest.session(session);
1123 modelBuildingRequest.requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT);
1124 modelBuildingRequest.profiles(
1125 request.getProfiles() != null
1126 ? request.getProfiles().stream()
1127 .map(org.apache.maven.model.Profile::getDelegate)
1128 .toList()
1129 : null);
1130 modelBuildingRequest.activeProfileIds(request.getActiveProfileIds());
1131 modelBuildingRequest.inactiveProfileIds(request.getInactiveProfileIds());
1132 modelBuildingRequest.systemProperties(toMap(request.getSystemProperties()));
1133 modelBuildingRequest.userProperties(toMap(request.getUserProperties()));
1134 modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf(
1135 request.getRepositoryMerging().name()));
1136 modelBuildingRequest.repositories(request.getRemoteRepositories().stream()
1137 .map(r -> session.getRemoteRepository(RepositoryUtils.toRepo(r)))
1138 .toList());
1139 return modelBuildingRequest;
1140 }
1141
1142 private DependencyResolutionResult resolveDependencies(MavenProject project) {
1143 DependencyResolutionResult resolutionResult;
1144
1145 RepositorySystemSession session = this.session.getSession();
1146 try {
1147 DefaultDependencyResolutionRequest resolution =
1148 new DefaultDependencyResolutionRequest(project, session);
1149 resolutionResult = dependencyResolver.resolve(resolution);
1150 } catch (DependencyResolutionException e) {
1151 resolutionResult = e.getResult();
1152 }
1153
1154 Set<Artifact> artifacts = new LinkedHashSet<>();
1155 if (resolutionResult.getDependencyGraph() != null) {
1156 RepositoryUtils.toArtifacts(
1157 artifacts,
1158 resolutionResult.getDependencyGraph().getChildren(),
1159 Collections.singletonList(project.getArtifact().getId()),
1160 null);
1161
1162
1163 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
1164 for (Artifact artifact : artifacts) {
1165 if (!artifact.isResolved()) {
1166 Path path = lrm.getAbsolutePathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
1167 artifact.setFile(path.toFile());
1168 }
1169 }
1170 }
1171 project.setResolvedArtifacts(artifacts);
1172 project.setArtifacts(artifacts);
1173
1174 return resolutionResult;
1175 }
1176 }
1177
1178 private static List<String> getProfileIds(List<Profile> profiles) {
1179 return profiles.stream().map(Profile::getId).toList();
1180 }
1181
1182 private static ModelSource createStubModelSource(Artifact artifact) {
1183 String xml = "<?xml version='1.0'?>" + "<project>"
1184 + "<modelVersion>4.0.0</modelVersion>"
1185 + "<groupId>"
1186 + artifact.getGroupId() + "</groupId>" + "<artifactId>"
1187 + artifact.getArtifactId() + "</artifactId>" + "<version>"
1188 + artifact.getBaseVersion() + "</version>" + "<packaging>"
1189 + artifact.getType() + "</packaging>" + "</project>";
1190 return new StubModelSource(xml, artifact);
1191 }
1192
1193
1194
1195
1196
1197 private static String extractProjectId(ModelBuilderResult result) {
1198 Model model = null;
1199 if (result.getEffectiveModel() != null) {
1200 model = result.getEffectiveModel();
1201 } else if (result.getRawModel() != null) {
1202 model = result.getRawModel();
1203 } else if (result.getFileModel() != null) {
1204 model = result.getFileModel();
1205 }
1206
1207 if (model != null) {
1208 return model.getId();
1209 }
1210
1211 return "";
1212 }
1213
1214 static String getGroupId(Model model) {
1215 String groupId = model.getGroupId();
1216 if (groupId == null && model.getParent() != null) {
1217 groupId = model.getParent().getGroupId();
1218 }
1219 return groupId;
1220 }
1221
1222 static String getVersion(Model model) {
1223 String version = model.getVersion();
1224 if (version == null && model.getParent() != null) {
1225 version = model.getParent().getVersion();
1226 }
1227 return version;
1228 }
1229
1230 private static Map<String, String> toMap(Properties properties) {
1231 if (properties != null && !properties.isEmpty()) {
1232 return properties.entrySet().stream()
1233 .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue())));
1234 } else {
1235 return null;
1236 }
1237 }
1238
1239 static class LazyMap<K, V> extends AbstractMap<K, V> {
1240 private final Supplier<Map<K, V>> supplier;
1241 private volatile Map<K, V> delegate;
1242
1243 LazyMap(Supplier<Map<K, V>> supplier) {
1244 this.supplier = supplier;
1245 }
1246
1247 @Override
1248 public Set<Entry<K, V>> entrySet() {
1249 if (delegate == null) {
1250 synchronized (this) {
1251 if (delegate == null) {
1252 delegate = supplier.get();
1253 }
1254 }
1255 }
1256 return delegate.entrySet();
1257 }
1258 }
1259
1260 private Model injectLifecycleBindings(
1261 Model model,
1262 ModelBuilderRequest request,
1263 ModelProblemCollector problems,
1264 MavenProject project,
1265 ProjectBuildingRequest projectBuildingRequest) {
1266 org.apache.maven.model.Model model3 = new org.apache.maven.model.Model(model);
1267 List<ArtifactRepository> remoteRepositories = projectBuildingRequest.getRemoteRepositories();
1268 List<ArtifactRepository> pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
1269 try {
1270 pluginRepositories = projectBuildingHelper.createArtifactRepositories(
1271 model3.getPluginRepositories(), pluginRepositories, projectBuildingRequest);
1272 } catch (Exception e) {
1273 problems.add(Severity.ERROR, Version.BASE, "Invalid plugin repository: " + e.getMessage(), e);
1274 }
1275 project.setPluginArtifactRepositories(pluginRepositories);
1276
1277 if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_PROJECT) {
1278 try {
1279 ProjectRealmCache.CacheRecord record =
1280 projectBuildingHelper.createProjectRealm(project, model3, projectBuildingRequest);
1281
1282 project.setClassRealm(record.getRealm());
1283 project.setExtensionDependencyFilter(record.getExtensionArtifactFilter());
1284 } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) {
1285
1286 problems.add(Severity.ERROR, Version.BASE, "Unresolvable build extension: " + e.getMessage(), e);
1287 }
1288 projectBuildingHelper.selectProjectRealm(project);
1289 }
1290
1291
1292 try {
1293 remoteRepositories = projectBuildingHelper.createArtifactRepositories(
1294 model3.getRepositories(), remoteRepositories, projectBuildingRequest);
1295 } catch (Exception e) {
1296 problems.add(Severity.ERROR, Version.BASE, "Invalid artifact repository: " + e.getMessage(), e);
1297 }
1298 project.setRemoteArtifactRepositories(remoteRepositories);
1299
1300 if (projectBuildingRequest.isProcessPlugins()) {
1301 return lifecycleBindingsInjector.injectLifecycleBindings(model3.getDelegate(), request, problems);
1302 } else {
1303 return model3.getDelegate();
1304 }
1305 }
1306 }