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