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 ProjectBuildingResult build(
443 boolean parent, Artifact artifact, boolean allowStubModel, List<ArtifactRepository> repositories)
444 throws ProjectBuildingException {
445 org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
446 pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
447
448 boolean localProject;
449
450 try {
451 ArtifactCoordinates coordinates = session.createArtifactCoordinates(session.getArtifact(pomArtifact));
452
453 ArtifactResolverRequest req = ArtifactResolverRequest.builder()
454 .session(session)
455 .repositories(repositories.stream()
456 .map(RepositoryUtils::toRepo)
457 .map(session::getRemoteRepository)
458 .toList())
459 .coordinates(List.of(coordinates))
460 .build();
461 ArtifactResolverResult res =
462 session.getService(ArtifactResolver.class).resolve(req);
463 ArtifactResolverResult.ResultItem resItem = res.getResult(coordinates);
464
465 pomArtifact = InternalMavenSession.from(session).toArtifact(resItem.getArtifact());
466 localProject = resItem.getRepository() instanceof org.apache.maven.api.WorkspaceRepository;
467 } catch (ArtifactResolverException e) {
468 if (e.getResult().getResults().values().iterator().next().isMissing() && allowStubModel) {
469 return build(parent, null, createStubModelSource(artifact));
470 }
471 throw new ProjectBuildingException(
472 artifact.getId(), "Error resolving project artifact: " + e.getMessage(), e);
473 }
474
475 Path pomFile = pomArtifact.getPath();
476
477 if (!artifact.isResolved() && "pom".equals(artifact.getType())) {
478 artifact.selectVersion(pomArtifact.getVersion());
479 artifact.setFile(pomFile.toFile());
480 artifact.setResolved(true);
481 }
482
483 if (localProject) {
484 return build(parent, pomFile, Sources.buildSource(pomFile));
485 } else {
486 return build(
487 parent,
488 null,
489 Sources.resolvedSource(
490 pomFile,
491 artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()));
492 }
493 }
494
495 List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive) throws ProjectBuildingException {
496 List<ProjectBuildingResult> results = doBuild(pomFiles, recursive);
497 if (results.stream()
498 .flatMap(r -> r.getProblems().stream())
499 .anyMatch(p -> p.getSeverity() != org.apache.maven.model.building.ModelProblem.Severity.WARNING)) {
500 org.apache.maven.model.building.ModelProblem cycle = results.stream()
501 .flatMap(r -> r.getProblems().stream())
502 .filter(p -> p.getException() instanceof CycleDetectedException)
503 .findAny()
504 .orElse(null);
505 if (cycle != null) {
506 final CycleDetectedException cde = (CycleDetectedException) cycle.getException();
507 throw new ProjectBuildingException(
508 null,
509 "The projects in the reactor contain a cyclic reference: " + cycle.getMessage(),
510 null,
511 cde);
512 }
513
514 throw new ProjectBuildingException(results);
515 }
516
517 return results;
518 }
519
520 List<ProjectBuildingResult> doBuild(List<File> pomFiles, boolean recursive) {
521 ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
522 try {
523 return pomFiles.stream()
524 .map(pomFile -> build(pomFile, recursive))
525 .flatMap(List::stream)
526 .toList();
527 } finally {
528 Thread.currentThread().setContextClassLoader(oldContextClassLoader);
529 }
530 }
531
532 @SuppressWarnings("checkstyle:parameternumber")
533 private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
534 ModelBuilderResult result;
535 try {
536 ModelTransformer injector = (m, r, p) -> {
537 MavenProject project = projectIndex.computeIfAbsent(m.getId(), f -> new MavenProject());
538 return injectLifecycleBindings(m, r, p, project, request);
539 };
540 ModelBuilderRequest modelBuildingRequest = getModelBuildingRequest()
541 .source(Sources.buildSource(pomFile.toPath()))
542 .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT)
543 .locationTracking(true)
544 .recursive(recursive)
545 .lifecycleBindingsInjector(injector)
546 .build();
547 result = modelBuilderSession.build(modelBuildingRequest);
548 } catch (ModelBuilderException e) {
549 result = e.getResult();
550 if (result == null || result.getEffectiveModel() == null) {
551 return List.of(new DefaultProjectBuildingResult(
552 e.getModelId(), pomFile, convert(e.getProblemCollector())));
553 }
554 }
555
556 List<ProjectBuildingResult> results = new ArrayList<>();
557 List<ModelBuilderResult> allModels = results(result).toList();
558 for (ModelBuilderResult r : allModels) {
559 if (r.getEffectiveModel() != null) {
560 File pom = r.getSource().getPath().toFile();
561 MavenProject project =
562 projectIndex.get(r.getEffectiveModel().getId());
563 project.setRootDirectory(
564 rootLocator.findRoot(pom.getParentFile().toPath()));
565 project.setFile(pom);
566 project.setExecutionRoot(pom.equals(pomFile));
567 initProject(project, r);
568 project.setCollectedProjects(results(r)
569 .filter(cr -> cr != r && cr.getEffectiveModel() != null)
570 .map(cr -> projectIndex.get(cr.getEffectiveModel().getId()))
571 .toList());
572
573 DependencyResolutionResult resolutionResult = null;
574 if (request.isResolveDependencies()) {
575 resolutionResult = resolveDependencies(project);
576 }
577 results.add(new DefaultProjectBuildingResult(
578 project, convert(r.getProblemCollector()), resolutionResult));
579 } else {
580
581 String projectId = extractProjectId(r);
582 File sourcePomFile = r.getSource() != null && r.getSource().getPath() != null
583 ? r.getSource().getPath().toFile()
584 : null;
585 results.add(new DefaultProjectBuildingResult(
586 projectId, sourcePomFile, convert(r.getProblemCollector())));
587 }
588 }
589 return results;
590 }
591
592 private Stream<ModelBuilderResult> results(ModelBuilderResult result) {
593 return Stream.concat(result.getChildren().stream().flatMap(this::results), Stream.of(result));
594 }
595
596 private List<org.apache.maven.model.building.ModelProblem> convert(
597 ProblemCollector<ModelProblem> problemCollector) {
598 if (problemCollector == null) {
599 return null;
600 }
601 ArrayList<org.apache.maven.model.building.ModelProblem> problems = new ArrayList<>();
602 problemCollector.problems().map(BuildSession::convert).forEach(problems::add);
603 if (problemCollector.problemsOverflow()) {
604 problems.add(
605 0,
606 new DefaultModelProblem(
607 "Too many model problems reported (listed problems are just a subset of reported problems)",
608 org.apache.maven.model.building.ModelProblem.Severity.WARNING,
609 null,
610 null,
611 -1,
612 -1,
613 null,
614 null));
615 return new ArrayList<>(problems) {
616 @Override
617 public int size() {
618 return problemCollector.totalProblemsReported();
619 }
620 };
621 } else {
622 return problems;
623 }
624 }
625
626 private static org.apache.maven.model.building.ModelProblem convert(ModelProblem p) {
627 return new DefaultModelProblem(
628 p.getMessage(),
629 org.apache.maven.model.building.ModelProblem.Severity.valueOf(
630 p.getSeverity().name()),
631 org.apache.maven.model.building.ModelProblem.Version.valueOf(
632 p.getVersion().name()),
633 p.getSource(),
634 p.getLineNumber(),
635 p.getColumnNumber(),
636 p.getModelId(),
637 p.getException());
638 }
639
640 @SuppressWarnings({"checkstyle:methodlength", "deprecation"})
641 private void initProject(MavenProject project, ModelBuilderResult result) {
642 project.setModel(new org.apache.maven.model.Model(result.getEffectiveModel()));
643 project.setOriginalModel(new org.apache.maven.model.Model(result.getFileModel()));
644
645 initParent(project, result);
646
647 Artifact projectArtifact = repositorySystem.createArtifact(
648 project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging());
649 project.setArtifact(projectArtifact);
650
651
652 if (project.getFile() != null) {
653 Build build = project.getBuild().getDelegate();
654 Path baseDir = project.getBaseDirectory();
655 Function<ProjectScope, String> outputDirectory = (scope) -> {
656 if (scope == ProjectScope.MAIN) {
657 return build.getOutputDirectory();
658 } else if (scope == ProjectScope.TEST) {
659 return build.getTestOutputDirectory();
660 } else {
661 return build.getDirectory();
662 }
663 };
664
665 final SourceHandlingContext sourceContext = new SourceHandlingContext(project, result);
666
667
668 for (org.apache.maven.api.model.Source source : sourceContext.sources) {
669 var sourceRoot = DefaultSourceRoot.fromModel(session, baseDir, outputDirectory, source);
670
671
672 if (sourceContext.shouldAddSource(sourceRoot)) {
673 project.addSourceRoot(sourceRoot);
674 }
675 }
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697 if (sourceContext.sources.isEmpty()) {
698
699 project.addScriptSourceRoot(build.getScriptSourceDirectory());
700 project.addCompileSourceRoot(build.getSourceDirectory());
701 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
702
703 sourceContext.handleResourceConfiguration(ProjectScope.MAIN);
704 sourceContext.handleResourceConfiguration(ProjectScope.TEST);
705 } else {
706
707 if (!sourceContext.hasSources(Language.SCRIPT, ProjectScope.MAIN)) {
708 project.addScriptSourceRoot(build.getScriptSourceDirectory());
709 }
710 if (sourceContext.usesModuleSourceHierarchy()) {
711
712 failIfLegacyDirectoryPresent(
713 build.getSourceDirectory(),
714 baseDir.resolve("src/main/java"),
715 "<sourceDirectory>",
716 project.getId(),
717 result,
718 true);
719 failIfLegacyDirectoryPresent(
720 build.getTestSourceDirectory(),
721 baseDir.resolve("src/test/java"),
722 "<testSourceDirectory>",
723 project.getId(),
724 result,
725 true);
726 } else {
727
728 Path mainDefault = baseDir.resolve("src/main/java");
729 Path testDefault = baseDir.resolve("src/test/java");
730
731 failIfLegacyDirectoryPresent(
732 build.getSourceDirectory(),
733 mainDefault,
734 "<sourceDirectory>",
735 project.getId(),
736 result,
737 false);
738 failIfLegacyDirectoryPresent(
739 build.getTestSourceDirectory(),
740 testDefault,
741 "<testSourceDirectory>",
742 project.getId(),
743 result,
744 false);
745
746
747
748
749 if (!sourceContext.hasSources(Language.JAVA_FAMILY, ProjectScope.MAIN)) {
750 Path configuredMain = Path.of(build.getSourceDirectory())
751 .toAbsolutePath()
752 .normalize();
753 if (configuredMain.equals(
754 mainDefault.toAbsolutePath().normalize())) {
755 project.addCompileSourceRoot(build.getSourceDirectory());
756 }
757 }
758 if (!sourceContext.hasSources(Language.JAVA_FAMILY, ProjectScope.TEST)) {
759 Path configuredTest = Path.of(build.getTestSourceDirectory())
760 .toAbsolutePath()
761 .normalize();
762 if (configuredTest.equals(
763 testDefault.toAbsolutePath().normalize())) {
764 project.addTestCompileSourceRoot(build.getTestSourceDirectory());
765 }
766 }
767 }
768
769
770 sourceContext.failIfMixedModularAndClassicSources();
771
772
773 sourceContext.handleResourceConfiguration(ProjectScope.MAIN);
774 sourceContext.handleResourceConfiguration(ProjectScope.TEST);
775 }
776
777
778
779
780 if (sourceContext.hasSources(Language.RESOURCES, ProjectScope.MAIN)
781 || sourceContext.hasSources(Language.RESOURCES, ProjectScope.TEST)) {
782 project.syncBuildResources();
783 }
784 }
785
786 project.setActiveProfiles(
787 Stream.concat(result.getActivePomProfiles().stream(), result.getActiveExternalProfiles().stream())
788 .map(org.apache.maven.model.Profile::new)
789 .toList());
790
791 project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
792
793
794 Map<String, List<org.apache.maven.api.model.Profile>> profilesByModel =
795 result.getActivePomProfilesByModel();
796
797 if (profilesByModel.isEmpty()) {
798
799
800 project.setInjectedProfileIds(
801 getModelDataId(result.getEffectiveModel()), getProfileIds(result.getActivePomProfiles()));
802 } else {
803 for (Map.Entry<String, List<org.apache.maven.api.model.Profile>> entry : profilesByModel.entrySet()) {
804 project.setInjectedProfileIds(entry.getKey(), getProfileIds(entry.getValue()));
805 }
806 }
807
808
809
810
811
812 project.setProjectBuildingRequest(request);
813
814
815 Set<Artifact> pluginArtifacts = new HashSet<>();
816 for (Plugin plugin : project.getModel().getDelegate().getBuild().getPlugins()) {
817 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(plugin));
818
819 if (artifact != null) {
820 pluginArtifacts.add(artifact);
821 }
822 }
823 project.setPluginArtifacts(pluginArtifacts);
824
825
826 Set<Artifact> reportArtifacts = new HashSet<>();
827 for (ReportPlugin report :
828 project.getModel().getDelegate().getReporting().getPlugins()) {
829 Plugin pp = Plugin.newBuilder()
830 .groupId(report.getGroupId())
831 .artifactId(report.getArtifactId())
832 .version(report.getVersion())
833 .build();
834
835 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(pp));
836
837 if (artifact != null) {
838 reportArtifacts.add(artifact);
839 }
840 }
841 project.setReportArtifacts(reportArtifacts);
842
843
844 Set<Artifact> extensionArtifacts = new HashSet<>();
845 List<Extension> extensions =
846 project.getModel().getDelegate().getBuild().getExtensions();
847 if (extensions != null) {
848 for (Extension ext : extensions) {
849 String version;
850 if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
851 version = "RELEASE";
852 } else {
853 version = ext.getVersion();
854 }
855
856 Artifact artifact = repositorySystem.createArtifact(
857 ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
858
859 if (artifact != null) {
860 extensionArtifacts.add(artifact);
861 }
862 }
863 }
864 project.setExtensionArtifacts(extensionArtifacts);
865
866
867 Map<String, Artifact> map = Collections.emptyMap();
868 final DependencyManagement dependencyManagement =
869 project.getModel().getDelegate().getDependencyManagement();
870 if (dependencyManagement != null
871 && dependencyManagement.getDependencies() != null
872 && !dependencyManagement.getDependencies().isEmpty()) {
873 map = new LazyMap<>(() -> {
874 Map<String, Artifact> tmp = new HashMap<>();
875 for (Dependency d : dependencyManagement.getDependencies()) {
876 Artifact artifact =
877 repositorySystem.createDependencyArtifact(new org.apache.maven.model.Dependency(d));
878 if (artifact != null) {
879 tmp.put(d.getManagementKey(), artifact);
880 }
881 }
882 return Collections.unmodifiableMap(tmp);
883 });
884 }
885 project.setManagedVersionMap(map);
886
887
888 if (project.getDistributionManagement() != null
889 && project.getDistributionManagement().getRepository() != null) {
890 try {
891 DeploymentRepository r = project.getModel()
892 .getDelegate()
893 .getDistributionManagement()
894 .getRepository();
895 if (r.getId() != null
896 && !r.getId().isEmpty()
897 && r.getUrl() != null
898 && !r.getUrl().isEmpty()) {
899 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
900 new org.apache.maven.model.DeploymentRepository(r));
901 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
902 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
903 project.setReleaseArtifactRepository(repo);
904 }
905 } catch (InvalidRepositoryException e) {
906 throw new IllegalStateException(
907 "Failed to create release distribution repository for " + project.getId(), e);
908 }
909 }
910
911
912 if (project.getDistributionManagement() != null
913 && project.getDistributionManagement().getSnapshotRepository() != null) {
914 try {
915 DeploymentRepository r = project.getModel()
916 .getDelegate()
917 .getDistributionManagement()
918 .getSnapshotRepository();
919 if (r.getId() != null
920 && !r.getId().isEmpty()
921 && r.getUrl() != null
922 && !r.getUrl().isEmpty()) {
923 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
924 new org.apache.maven.model.DeploymentRepository(r));
925 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
926 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
927 project.setSnapshotArtifactRepository(repo);
928 }
929 } catch (InvalidRepositoryException e) {
930 throw new IllegalStateException(
931 "Failed to create snapshot distribution repository for " + project.getId(), e);
932 }
933 }
934
935
936 List<ArtifactRepository> remoteRepositories = request.getRemoteRepositories();
937 try {
938 remoteRepositories = projectBuildingHelper.createArtifactRepositories(
939 project.getModel().getRepositories(), remoteRepositories, request);
940 } catch (Exception e) {
941 result.getProblemCollector()
942 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
943 "",
944 Severity.ERROR,
945 Version.BASE,
946 project.getModel().getDelegate(),
947 -1,
948 -1,
949 e));
950 }
951 project.setRemoteArtifactRepositories(remoteRepositories);
952 }
953
954
955
956
957 private static String getModelDataId(Model model) {
958 return ((model.getGroupId() == null) ? "[inherited]" : model.getGroupId()) + ":"
959 + model.getArtifactId()
960 + ":"
961 + ((model.getVersion() == null) ? "[inherited]" : model.getVersion());
962 }
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988 private void failIfLegacyDirectoryPresent(
989 String configuredDir,
990 Path defaultDir,
991 String elementName,
992 String projectId,
993 ModelBuilderResult result,
994 boolean checkPhysicalPresence) {
995 if (configuredDir != null) {
996 Path configuredPath = Path.of(configuredDir).toAbsolutePath().normalize();
997 Path defaultPath = defaultDir.toAbsolutePath().normalize();
998 if (!configuredPath.equals(defaultPath)) {
999
1000 String message = String.format(
1001 "Legacy %s cannot be used in project %s because sources are configured via <sources>. "
1002 + "Remove the %s configuration.",
1003 elementName, projectId, elementName);
1004 logger.error(message);
1005 result.getProblemCollector()
1006 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
1007 message, Severity.ERROR, Version.V41, null, -1, -1, null));
1008 } else if (checkPhysicalPresence && Files.isDirectory(defaultPath)) {
1009
1010 String message = String.format(
1011 "Legacy directory '%s' exists but cannot be used in project %s "
1012 + "because sources are configured via <sources>. "
1013 + "Remove or rename the directory.",
1014 defaultPath, projectId);
1015 logger.error(message);
1016 result.getProblemCollector()
1017 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
1018 message, Severity.ERROR, Version.V41, null, -1, -1, null));
1019 }
1020 }
1021 }
1022
1023 private void initParent(MavenProject project, ModelBuilderResult result) {
1024 Model parentModel = result.getParentModel();
1025
1026 if (parentModel != null) {
1027 final String parentGroupId = getGroupId(parentModel);
1028 final String parentVersion = getVersion(parentModel);
1029
1030 project.setParentArtifact(repositorySystem.createProjectArtifact(
1031 parentGroupId, parentModel.getArtifactId(), parentVersion));
1032
1033 MavenProject parent = projectIndex.get(parentModel.getId());
1034 if (parent == null) {
1035
1036
1037
1038
1039
1040
1041
1042 List<ArtifactRepository> mergedRepositories;
1043 switch (request.getRepositoryMerging()) {
1044 case POM_DOMINANT -> {
1045 LinkedHashSet<ArtifactRepository> reposes =
1046 new LinkedHashSet<>(project.getRemoteArtifactRepositories());
1047 reposes.addAll(request.getRemoteRepositories());
1048 mergedRepositories = List.copyOf(reposes);
1049 }
1050 case REQUEST_DOMINANT -> {
1051 LinkedHashSet<ArtifactRepository> reposes =
1052 new LinkedHashSet<>(request.getRemoteRepositories());
1053 reposes.addAll(project.getRemoteArtifactRepositories());
1054 mergedRepositories = List.copyOf(reposes);
1055 }
1056 default ->
1057 throw new IllegalArgumentException(
1058 "Unsupported repository merging: " + request.getRepositoryMerging());
1059 }
1060
1061
1062
1063 projectRepositories.put(project.getId(), mergedRepositories);
1064
1065 Path parentPomFile = parentModel.getPomFile();
1066 if (parentPomFile != null) {
1067 project.setParentFile(parentPomFile.toFile());
1068 try {
1069 parent = build(true, parentPomFile, Sources.buildSource(parentPomFile))
1070 .getProject();
1071 } catch (ProjectBuildingException e) {
1072
1073 if (logger.isDebugEnabled()) {
1074
1075 logger.warn("Failed to build parent project for " + project.getId(), e);
1076 } else {
1077
1078 logger.warn("Failed to build parent project for " + project.getId());
1079 }
1080 }
1081 } else {
1082 Artifact parentArtifact = project.getParentArtifact();
1083 try {
1084 parent = build(true, parentArtifact, false, getEffectiveRepositories(project.getId()))
1085 .getProject();
1086 } catch (ProjectBuildingException e) {
1087
1088 if (logger.isDebugEnabled()) {
1089
1090 logger.warn("Failed to build parent project for " + project.getId(), e);
1091 } else {
1092
1093 logger.warn("Failed to build parent project for " + project.getId());
1094 }
1095 }
1096 }
1097 }
1098 project.setParent(parent);
1099 if (project.getParentFile() == null && parent != null) {
1100 project.setParentFile(parent.getFile());
1101 }
1102 }
1103 }
1104
1105 private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() {
1106 ModelBuilderRequest.ModelBuilderRequestBuilder modelBuildingRequest = ModelBuilderRequest.builder();
1107
1108 modelBuildingRequest.session(session);
1109 modelBuildingRequest.requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT);
1110 modelBuildingRequest.profiles(
1111 request.getProfiles() != null
1112 ? request.getProfiles().stream()
1113 .map(org.apache.maven.model.Profile::getDelegate)
1114 .toList()
1115 : null);
1116 modelBuildingRequest.activeProfileIds(request.getActiveProfileIds());
1117 modelBuildingRequest.inactiveProfileIds(request.getInactiveProfileIds());
1118 modelBuildingRequest.systemProperties(toMap(request.getSystemProperties()));
1119 modelBuildingRequest.userProperties(toMap(request.getUserProperties()));
1120 modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf(
1121 request.getRepositoryMerging().name()));
1122 modelBuildingRequest.repositories(request.getRemoteRepositories().stream()
1123 .map(r -> session.getRemoteRepository(RepositoryUtils.toRepo(r)))
1124 .toList());
1125 return modelBuildingRequest;
1126 }
1127
1128 private DependencyResolutionResult resolveDependencies(MavenProject project) {
1129 DependencyResolutionResult resolutionResult;
1130
1131 RepositorySystemSession session = this.session.getSession();
1132 try {
1133 DefaultDependencyResolutionRequest resolution =
1134 new DefaultDependencyResolutionRequest(project, session);
1135 resolutionResult = dependencyResolver.resolve(resolution);
1136 } catch (DependencyResolutionException e) {
1137 resolutionResult = e.getResult();
1138 }
1139
1140 Set<Artifact> artifacts = new LinkedHashSet<>();
1141 if (resolutionResult.getDependencyGraph() != null) {
1142 RepositoryUtils.toArtifacts(
1143 artifacts,
1144 resolutionResult.getDependencyGraph().getChildren(),
1145 Collections.singletonList(project.getArtifact().getId()),
1146 null);
1147
1148
1149 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
1150 for (Artifact artifact : artifacts) {
1151 if (!artifact.isResolved()) {
1152 Path path = lrm.getAbsolutePathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
1153 artifact.setFile(path.toFile());
1154 }
1155 }
1156 }
1157 project.setResolvedArtifacts(artifacts);
1158 project.setArtifacts(artifacts);
1159
1160 return resolutionResult;
1161 }
1162 }
1163
1164 private static List<String> getProfileIds(List<Profile> profiles) {
1165 return profiles.stream().map(Profile::getId).toList();
1166 }
1167
1168 private static ModelSource createStubModelSource(Artifact artifact) {
1169 String xml = "<?xml version='1.0'?>" + "<project>"
1170 + "<modelVersion>4.0.0</modelVersion>"
1171 + "<groupId>"
1172 + artifact.getGroupId() + "</groupId>" + "<artifactId>"
1173 + artifact.getArtifactId() + "</artifactId>" + "<version>"
1174 + artifact.getBaseVersion() + "</version>" + "<packaging>"
1175 + artifact.getType() + "</packaging>" + "</project>";
1176 return new StubModelSource(xml, artifact);
1177 }
1178
1179
1180
1181
1182
1183 private static String extractProjectId(ModelBuilderResult result) {
1184 Model model = null;
1185 if (result.getEffectiveModel() != null) {
1186 model = result.getEffectiveModel();
1187 } else if (result.getRawModel() != null) {
1188 model = result.getRawModel();
1189 } else if (result.getFileModel() != null) {
1190 model = result.getFileModel();
1191 }
1192
1193 if (model != null) {
1194 return model.getId();
1195 }
1196
1197 return "";
1198 }
1199
1200 static String getGroupId(Model model) {
1201 String groupId = model.getGroupId();
1202 if (groupId == null && model.getParent() != null) {
1203 groupId = model.getParent().getGroupId();
1204 }
1205 return groupId;
1206 }
1207
1208 static String getVersion(Model model) {
1209 String version = model.getVersion();
1210 if (version == null && model.getParent() != null) {
1211 version = model.getParent().getVersion();
1212 }
1213 return version;
1214 }
1215
1216 private static Map<String, String> toMap(Properties properties) {
1217 if (properties != null && !properties.isEmpty()) {
1218 return properties.entrySet().stream()
1219 .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue())));
1220 } else {
1221 return null;
1222 }
1223 }
1224
1225 static class LazyMap<K, V> extends AbstractMap<K, V> {
1226 private final Supplier<Map<K, V>> supplier;
1227 private volatile Map<K, V> delegate;
1228
1229 LazyMap(Supplier<Map<K, V>> supplier) {
1230 this.supplier = supplier;
1231 }
1232
1233 @Override
1234 public Set<Entry<K, V>> entrySet() {
1235 if (delegate == null) {
1236 synchronized (this) {
1237 if (delegate == null) {
1238 delegate = supplier.get();
1239 }
1240 }
1241 }
1242 return delegate.entrySet();
1243 }
1244 }
1245
1246 private Model injectLifecycleBindings(
1247 Model model,
1248 ModelBuilderRequest request,
1249 ModelProblemCollector problems,
1250 MavenProject project,
1251 ProjectBuildingRequest projectBuildingRequest) {
1252 org.apache.maven.model.Model model3 = new org.apache.maven.model.Model(model);
1253 List<ArtifactRepository> remoteRepositories = projectBuildingRequest.getRemoteRepositories();
1254 List<ArtifactRepository> pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
1255 try {
1256 pluginRepositories = projectBuildingHelper.createArtifactRepositories(
1257 model3.getPluginRepositories(), pluginRepositories, projectBuildingRequest);
1258 } catch (Exception e) {
1259 problems.add(Severity.ERROR, Version.BASE, "Invalid plugin repository: " + e.getMessage(), e);
1260 }
1261 project.setPluginArtifactRepositories(pluginRepositories);
1262
1263 if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_PROJECT) {
1264 try {
1265 ProjectRealmCache.CacheRecord record =
1266 projectBuildingHelper.createProjectRealm(project, model3, projectBuildingRequest);
1267
1268 project.setClassRealm(record.getRealm());
1269 project.setExtensionDependencyFilter(record.getExtensionArtifactFilter());
1270 } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) {
1271
1272 problems.add(Severity.ERROR, Version.BASE, "Unresolvable build extension: " + e.getMessage(), e);
1273 }
1274 projectBuildingHelper.selectProjectRealm(project);
1275 }
1276
1277
1278 try {
1279 remoteRepositories = projectBuildingHelper.createArtifactRepositories(
1280 model3.getRepositories(), remoteRepositories, projectBuildingRequest);
1281 } catch (Exception e) {
1282 problems.add(Severity.ERROR, Version.BASE, "Invalid artifact repository: " + e.getMessage(), e);
1283 }
1284 project.setRemoteArtifactRepositories(remoteRepositories);
1285
1286 if (projectBuildingRequest.isProcessPlugins()) {
1287 return lifecycleBindingsInjector.injectLifecycleBindings(model3.getDelegate(), request, problems);
1288 } else {
1289 return model3.getDelegate();
1290 }
1291 }
1292 }