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
783
784 if (sourceContext.hasSources(Language.RESOURCES, ProjectScope.MAIN)
785 || sourceContext.hasSources(Language.RESOURCES, ProjectScope.TEST)) {
786 project.syncBuildResources();
787 }
788 }
789
790 project.setActiveProfiles(
791 Stream.concat(result.getActivePomProfiles().stream(), result.getActiveExternalProfiles().stream())
792 .map(org.apache.maven.model.Profile::new)
793 .toList());
794
795 project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
796
797
798 Map<String, List<org.apache.maven.api.model.Profile>> profilesByModel =
799 result.getActivePomProfilesByModel();
800
801 if (profilesByModel.isEmpty()) {
802
803
804 project.setInjectedProfileIds(
805 result.getEffectiveModel().getId(), getProfileIds(result.getActivePomProfiles()));
806 } else {
807 for (Map.Entry<String, List<org.apache.maven.api.model.Profile>> entry : profilesByModel.entrySet()) {
808 project.setInjectedProfileIds(entry.getKey(), getProfileIds(entry.getValue()));
809 }
810 }
811
812
813
814
815
816 project.setProjectBuildingRequest(request);
817
818
819 Set<Artifact> pluginArtifacts = new HashSet<>();
820 for (Plugin plugin : project.getModel().getDelegate().getBuild().getPlugins()) {
821 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(plugin));
822
823 if (artifact != null) {
824 pluginArtifacts.add(artifact);
825 }
826 }
827 project.setPluginArtifacts(pluginArtifacts);
828
829
830 Set<Artifact> reportArtifacts = new HashSet<>();
831 for (ReportPlugin report :
832 project.getModel().getDelegate().getReporting().getPlugins()) {
833 Plugin pp = Plugin.newBuilder()
834 .groupId(report.getGroupId())
835 .artifactId(report.getArtifactId())
836 .version(report.getVersion())
837 .build();
838
839 Artifact artifact = repositorySystem.createPluginArtifact(new org.apache.maven.model.Plugin(pp));
840
841 if (artifact != null) {
842 reportArtifacts.add(artifact);
843 }
844 }
845 project.setReportArtifacts(reportArtifacts);
846
847
848 Set<Artifact> extensionArtifacts = new HashSet<>();
849 List<Extension> extensions =
850 project.getModel().getDelegate().getBuild().getExtensions();
851 if (extensions != null) {
852 for (Extension ext : extensions) {
853 String version;
854 if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
855 version = "RELEASE";
856 } else {
857 version = ext.getVersion();
858 }
859
860 Artifact artifact = repositorySystem.createArtifact(
861 ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
862
863 if (artifact != null) {
864 extensionArtifacts.add(artifact);
865 }
866 }
867 }
868 project.setExtensionArtifacts(extensionArtifacts);
869
870
871 Map<String, Artifact> map = Collections.emptyMap();
872 final DependencyManagement dependencyManagement =
873 project.getModel().getDelegate().getDependencyManagement();
874 if (dependencyManagement != null
875 && dependencyManagement.getDependencies() != null
876 && !dependencyManagement.getDependencies().isEmpty()) {
877 map = new LazyMap<>(() -> {
878 Map<String, Artifact> tmp = new HashMap<>();
879 for (Dependency d : dependencyManagement.getDependencies()) {
880 Artifact artifact =
881 repositorySystem.createDependencyArtifact(new org.apache.maven.model.Dependency(d));
882 if (artifact != null) {
883 tmp.put(d.getManagementKey(), artifact);
884 }
885 }
886 return Collections.unmodifiableMap(tmp);
887 });
888 }
889 project.setManagedVersionMap(map);
890
891
892 if (project.getDistributionManagement() != null
893 && project.getDistributionManagement().getRepository() != null) {
894 try {
895 DeploymentRepository r = project.getModel()
896 .getDelegate()
897 .getDistributionManagement()
898 .getRepository();
899 if (r.getId() != null
900 && !r.getId().isEmpty()
901 && r.getUrl() != null
902 && !r.getUrl().isEmpty()) {
903 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
904 new org.apache.maven.model.DeploymentRepository(r));
905 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
906 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
907 project.setReleaseArtifactRepository(repo);
908 }
909 } catch (InvalidRepositoryException e) {
910 throw new IllegalStateException(
911 "Failed to create release distribution repository for " + project.getId(), e);
912 }
913 }
914
915
916 if (project.getDistributionManagement() != null
917 && project.getDistributionManagement().getSnapshotRepository() != null) {
918 try {
919 DeploymentRepository r = project.getModel()
920 .getDelegate()
921 .getDistributionManagement()
922 .getSnapshotRepository();
923 if (r.getId() != null
924 && !r.getId().isEmpty()
925 && r.getUrl() != null
926 && !r.getUrl().isEmpty()) {
927 ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(
928 new org.apache.maven.model.DeploymentRepository(r));
929 repositorySystem.injectProxy(request.getRepositorySession(), List.of(repo));
930 repositorySystem.injectAuthentication(request.getRepositorySession(), List.of(repo));
931 project.setSnapshotArtifactRepository(repo);
932 }
933 } catch (InvalidRepositoryException e) {
934 throw new IllegalStateException(
935 "Failed to create snapshot distribution repository for " + project.getId(), e);
936 }
937 }
938
939
940 List<ArtifactRepository> remoteRepositories = request.getRemoteRepositories();
941 try {
942 remoteRepositories = projectBuildingHelper.createArtifactRepositories(
943 project.getModel().getRepositories(), remoteRepositories, request);
944 } catch (Exception e) {
945 result.getProblemCollector()
946 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
947 "",
948 Severity.ERROR,
949 Version.BASE,
950 project.getModel().getDelegate(),
951 -1,
952 -1,
953 e));
954 }
955 project.setRemoteArtifactRepositories(remoteRepositories);
956 }
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982 private void failIfLegacyDirectoryPresent(
983 String configuredDir,
984 Path defaultDir,
985 String elementName,
986 String projectId,
987 ModelBuilderResult result,
988 boolean checkPhysicalPresence) {
989 if (configuredDir != null) {
990 Path configuredPath = Path.of(configuredDir).toAbsolutePath().normalize();
991 Path defaultPath = defaultDir.toAbsolutePath().normalize();
992 if (!configuredPath.equals(defaultPath)) {
993
994 String message = String.format(
995 "Legacy %s cannot be used in project %s because sources are configured via <sources>. "
996 + "Remove the %s configuration.",
997 elementName, projectId, elementName);
998 logger.error(message);
999 result.getProblemCollector()
1000 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
1001 message, Severity.ERROR, Version.V41, null, -1, -1, null));
1002 } else if (checkPhysicalPresence && Files.isDirectory(defaultPath)) {
1003
1004 String message = String.format(
1005 "Legacy directory '%s' exists but cannot be used in project %s "
1006 + "because sources are configured via <sources>. "
1007 + "Remove or rename the directory.",
1008 defaultPath, projectId);
1009 logger.error(message);
1010 result.getProblemCollector()
1011 .reportProblem(new org.apache.maven.impl.model.DefaultModelProblem(
1012 message, Severity.ERROR, Version.V41, null, -1, -1, null));
1013 }
1014 }
1015 }
1016
1017 private void initParent(MavenProject project, ModelBuilderResult result) {
1018 Model parentModel = result.getParentModel();
1019
1020 if (parentModel != null) {
1021 final String parentGroupId = getGroupId(parentModel);
1022 final String parentVersion = getVersion(parentModel);
1023
1024 project.setParentArtifact(repositorySystem.createProjectArtifact(
1025 parentGroupId, parentModel.getArtifactId(), parentVersion));
1026
1027 MavenProject parent = projectIndex.get(parentModel.getId());
1028 if (parent == null) {
1029
1030
1031
1032
1033
1034
1035
1036 List<ArtifactRepository> mergedRepositories;
1037 switch (request.getRepositoryMerging()) {
1038 case POM_DOMINANT -> {
1039 LinkedHashSet<ArtifactRepository> reposes =
1040 new LinkedHashSet<>(project.getRemoteArtifactRepositories());
1041 reposes.addAll(request.getRemoteRepositories());
1042 mergedRepositories = List.copyOf(reposes);
1043 }
1044 case REQUEST_DOMINANT -> {
1045 LinkedHashSet<ArtifactRepository> reposes =
1046 new LinkedHashSet<>(request.getRemoteRepositories());
1047 reposes.addAll(project.getRemoteArtifactRepositories());
1048 mergedRepositories = List.copyOf(reposes);
1049 }
1050 default ->
1051 throw new IllegalArgumentException(
1052 "Unsupported repository merging: " + request.getRepositoryMerging());
1053 }
1054
1055
1056
1057 projectRepositories.put(project.getId(), mergedRepositories);
1058
1059 Path parentPomFile = parentModel.getPomFile();
1060 if (parentPomFile != null) {
1061 project.setParentFile(parentPomFile.toFile());
1062 try {
1063 parent = build(true, parentPomFile, Sources.buildSource(parentPomFile))
1064 .getProject();
1065 } catch (ProjectBuildingException e) {
1066
1067 if (logger.isDebugEnabled()) {
1068
1069 logger.warn("Failed to build parent project for " + project.getId(), e);
1070 } else {
1071
1072 logger.warn("Failed to build parent project for " + project.getId());
1073 }
1074 }
1075 } else {
1076 Artifact parentArtifact = project.getParentArtifact();
1077 try {
1078 parent = build(true, parentArtifact, false, getEffectiveRepositories(project.getId()))
1079 .getProject();
1080 } catch (ProjectBuildingException e) {
1081
1082 if (logger.isDebugEnabled()) {
1083
1084 logger.warn("Failed to build parent project for " + project.getId(), e);
1085 } else {
1086
1087 logger.warn("Failed to build parent project for " + project.getId());
1088 }
1089 }
1090 }
1091 }
1092 project.setParent(parent);
1093 if (project.getParentFile() == null && parent != null) {
1094 project.setParentFile(parent.getFile());
1095 }
1096 }
1097 }
1098
1099 private ModelBuilderRequest.ModelBuilderRequestBuilder getModelBuildingRequest() {
1100 ModelBuilderRequest.ModelBuilderRequestBuilder modelBuildingRequest = ModelBuilderRequest.builder();
1101
1102 modelBuildingRequest.session(session);
1103 modelBuildingRequest.requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT);
1104 modelBuildingRequest.profiles(
1105 request.getProfiles() != null
1106 ? request.getProfiles().stream()
1107 .map(org.apache.maven.model.Profile::getDelegate)
1108 .toList()
1109 : null);
1110 modelBuildingRequest.activeProfileIds(request.getActiveProfileIds());
1111 modelBuildingRequest.inactiveProfileIds(request.getInactiveProfileIds());
1112 modelBuildingRequest.systemProperties(toMap(request.getSystemProperties()));
1113 modelBuildingRequest.userProperties(toMap(request.getUserProperties()));
1114 modelBuildingRequest.repositoryMerging(ModelBuilderRequest.RepositoryMerging.valueOf(
1115 request.getRepositoryMerging().name()));
1116 modelBuildingRequest.repositories(request.getRemoteRepositories().stream()
1117 .map(r -> session.getRemoteRepository(RepositoryUtils.toRepo(r)))
1118 .toList());
1119 return modelBuildingRequest;
1120 }
1121
1122 private DependencyResolutionResult resolveDependencies(MavenProject project) {
1123 DependencyResolutionResult resolutionResult;
1124
1125 RepositorySystemSession session = this.session.getSession();
1126 try {
1127 DefaultDependencyResolutionRequest resolution =
1128 new DefaultDependencyResolutionRequest(project, session);
1129 resolutionResult = dependencyResolver.resolve(resolution);
1130 } catch (DependencyResolutionException e) {
1131 resolutionResult = e.getResult();
1132 }
1133
1134 Set<Artifact> artifacts = new LinkedHashSet<>();
1135 if (resolutionResult.getDependencyGraph() != null) {
1136 RepositoryUtils.toArtifacts(
1137 artifacts,
1138 resolutionResult.getDependencyGraph().getChildren(),
1139 Collections.singletonList(project.getArtifact().getId()),
1140 null);
1141
1142
1143 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
1144 for (Artifact artifact : artifacts) {
1145 if (!artifact.isResolved()) {
1146 Path path = lrm.getAbsolutePathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
1147 artifact.setFile(path.toFile());
1148 }
1149 }
1150 }
1151 project.setResolvedArtifacts(artifacts);
1152 project.setArtifacts(artifacts);
1153
1154 return resolutionResult;
1155 }
1156 }
1157
1158 private static List<String> getProfileIds(List<Profile> profiles) {
1159 return profiles.stream().map(Profile::getId).toList();
1160 }
1161
1162 private static ModelSource createStubModelSource(Artifact artifact) {
1163 String xml = "<?xml version='1.0'?>" + "<project>"
1164 + "<modelVersion>4.0.0</modelVersion>"
1165 + "<groupId>"
1166 + artifact.getGroupId() + "</groupId>" + "<artifactId>"
1167 + artifact.getArtifactId() + "</artifactId>" + "<version>"
1168 + artifact.getBaseVersion() + "</version>" + "<packaging>"
1169 + artifact.getType() + "</packaging>" + "</project>";
1170 return new StubModelSource(xml, artifact);
1171 }
1172
1173
1174
1175
1176
1177 private static String extractProjectId(ModelBuilderResult result) {
1178 Model model = null;
1179 if (result.getEffectiveModel() != null) {
1180 model = result.getEffectiveModel();
1181 } else if (result.getRawModel() != null) {
1182 model = result.getRawModel();
1183 } else if (result.getFileModel() != null) {
1184 model = result.getFileModel();
1185 }
1186
1187 if (model != null) {
1188 return model.getId();
1189 }
1190
1191 return "";
1192 }
1193
1194 static String getGroupId(Model model) {
1195 String groupId = model.getGroupId();
1196 if (groupId == null && model.getParent() != null) {
1197 groupId = model.getParent().getGroupId();
1198 }
1199 return groupId;
1200 }
1201
1202 static String getVersion(Model model) {
1203 String version = model.getVersion();
1204 if (version == null && model.getParent() != null) {
1205 version = model.getParent().getVersion();
1206 }
1207 return version;
1208 }
1209
1210 private static Map<String, String> toMap(Properties properties) {
1211 if (properties != null && !properties.isEmpty()) {
1212 return properties.entrySet().stream()
1213 .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue())));
1214 } else {
1215 return null;
1216 }
1217 }
1218
1219 static class LazyMap<K, V> extends AbstractMap<K, V> {
1220 private final Supplier<Map<K, V>> supplier;
1221 private volatile Map<K, V> delegate;
1222
1223 LazyMap(Supplier<Map<K, V>> supplier) {
1224 this.supplier = supplier;
1225 }
1226
1227 @Override
1228 public Set<Entry<K, V>> entrySet() {
1229 if (delegate == null) {
1230 synchronized (this) {
1231 if (delegate == null) {
1232 delegate = supplier.get();
1233 }
1234 }
1235 }
1236 return delegate.entrySet();
1237 }
1238 }
1239
1240 private Model injectLifecycleBindings(
1241 Model model,
1242 ModelBuilderRequest request,
1243 ModelProblemCollector problems,
1244 MavenProject project,
1245 ProjectBuildingRequest projectBuildingRequest) {
1246 org.apache.maven.model.Model model3 = new org.apache.maven.model.Model(model);
1247 List<ArtifactRepository> remoteRepositories = projectBuildingRequest.getRemoteRepositories();
1248 List<ArtifactRepository> pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
1249 try {
1250 pluginRepositories = projectBuildingHelper.createArtifactRepositories(
1251 model3.getPluginRepositories(), pluginRepositories, projectBuildingRequest);
1252 } catch (Exception e) {
1253 problems.add(Severity.ERROR, Version.BASE, "Invalid plugin repository: " + e.getMessage(), e);
1254 }
1255 project.setPluginArtifactRepositories(pluginRepositories);
1256
1257 if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_PROJECT) {
1258 try {
1259 ProjectRealmCache.CacheRecord record =
1260 projectBuildingHelper.createProjectRealm(project, model3, projectBuildingRequest);
1261
1262 project.setClassRealm(record.getRealm());
1263 project.setExtensionDependencyFilter(record.getExtensionArtifactFilter());
1264 } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) {
1265
1266 problems.add(Severity.ERROR, Version.BASE, "Unresolvable build extension: " + e.getMessage(), e);
1267 }
1268 projectBuildingHelper.selectProjectRealm(project);
1269 }
1270
1271
1272 try {
1273 remoteRepositories = projectBuildingHelper.createArtifactRepositories(
1274 model3.getRepositories(), remoteRepositories, projectBuildingRequest);
1275 } catch (Exception e) {
1276 problems.add(Severity.ERROR, Version.BASE, "Invalid artifact repository: " + e.getMessage(), e);
1277 }
1278 project.setRemoteArtifactRepositories(remoteRepositories);
1279
1280 if (projectBuildingRequest.isProcessPlugins()) {
1281 return lifecycleBindingsInjector.injectLifecycleBindings(model3.getDelegate(), request, problems);
1282 } else {
1283 return model3.getDelegate();
1284 }
1285 }
1286 }