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 java.io.File;
22 import java.nio.charset.StandardCharsets;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Optional;
29 import java.util.Properties;
30 import java.util.Set;
31 import java.util.concurrent.atomic.AtomicInteger;
32 import java.util.stream.Collectors;
33
34 import org.apache.maven.AbstractCoreMavenComponentTestCase;
35 import org.apache.maven.api.Language;
36 import org.apache.maven.api.ProjectScope;
37 import org.apache.maven.api.SourceRoot;
38 import org.apache.maven.execution.MavenSession;
39 import org.apache.maven.model.Dependency;
40 import org.apache.maven.model.InputLocation;
41 import org.apache.maven.model.Plugin;
42 import org.apache.maven.model.building.ModelBuildingRequest;
43 import org.apache.maven.model.building.ModelProblem;
44 import org.codehaus.plexus.util.FileUtils;
45 import org.junit.jupiter.api.Test;
46 import org.junit.jupiter.api.io.TempDir;
47
48 import static org.junit.jupiter.api.Assertions.assertEquals;
49 import static org.junit.jupiter.api.Assertions.assertFalse;
50 import static org.junit.jupiter.api.Assertions.assertNotNull;
51 import static org.junit.jupiter.api.Assertions.assertThrows;
52 import static org.junit.jupiter.api.Assertions.assertTrue;
53
54 class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
55 @Override
56 protected String getProjectsDirectory() {
57 return "src/test/projects/project-builder";
58 }
59
60 @Test
61 void testSystemScopeDependencyIsPresentInTheCompileClasspathElements() throws Exception {
62 File pom = getProject("it0063");
63
64 Properties eps = new Properties();
65 eps.setProperty("jre.home", new File(pom.getParentFile(), "jdk/jre").getPath());
66
67 MavenSession session = createMavenSession(pom, eps);
68 MavenProject project = session.getCurrentProject();
69
70
71
72
73 project.getCompileClasspathElements();
74 }
75
76 @Test
77 void testBuildFromModelSource() throws Exception {
78 File pomFile = new File("src/test/resources/projects/modelsource/module01/pom.xml");
79 MavenSession mavenSession = createMavenSession(pomFile);
80 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
81 configuration.setRepositorySession(mavenSession.getRepositorySession());
82 ProjectBuildingResult result = getContainer()
83 .lookup(org.apache.maven.project.ProjectBuilder.class)
84 .build(pomFile, configuration);
85
86 assertNotNull(result.getProject().getParentFile());
87 }
88
89 @Test
90 void testVersionlessManagedDependency() throws Exception {
91 File pomFile = new File("src/test/resources/projects/versionless-managed-dependency.xml");
92 MavenSession mavenSession = createMavenSession(null);
93 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
94 configuration.setRepositorySession(mavenSession.getRepositorySession());
95
96 ProjectBuildingException e = assertThrows(
97 ProjectBuildingException.class,
98 () -> getContainer()
99 .lookup(org.apache.maven.project.ProjectBuilder.class)
100 .build(pomFile, configuration));
101 assertEquals(1, e.getResults().size());
102 ProjectBuildingResultWithProblemMessageAssert.assertThat(e.getResults().get(0))
103 .hasProblemMessage(
104 "'dependencies.dependency.version' for groupId='org.apache.maven.its', artifactId='a', type='jar' is missing");
105 ProjectBuildingResultWithLocationAssert.assertThat(e.getResults().get(0))
106 .hasLocation(5, 9);
107 }
108
109 @Test
110 void testResolveDependencies() throws Exception {
111 File pomFile = new File("src/test/resources/projects/basic-resolveDependencies.xml");
112 MavenSession mavenSession = createMavenSession(null);
113 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
114 configuration.setRepositorySession(mavenSession.getRepositorySession());
115 configuration.setResolveDependencies(true);
116
117
118 ProjectBuildingResult result = getContainer()
119 .lookup(org.apache.maven.project.ProjectBuilder.class)
120 .build(pomFile, configuration);
121 assertEquals(1, result.getProject().getArtifacts().size());
122
123 List<ProjectBuildingResult> results = getContainer()
124 .lookup(org.apache.maven.project.ProjectBuilder.class)
125 .build(Collections.singletonList(pomFile), false, configuration);
126 assertEquals(1, results.size());
127 MavenProject mavenProject = results.get(0).getProject();
128 assertEquals(1, mavenProject.getArtifacts().size());
129
130 final MavenProject project = mavenProject;
131 final AtomicInteger artifactsResultInAnotherThread = new AtomicInteger();
132 Thread t = new Thread(new Runnable() {
133 @Override
134 public void run() {
135 artifactsResultInAnotherThread.set(project.getArtifacts().size());
136 }
137 });
138 t.start();
139 t.join();
140 assertEquals(project.getArtifacts().size(), artifactsResultInAnotherThread.get());
141 }
142
143 @Test
144 void testDontResolveDependencies() throws Exception {
145 File pomFile = new File("src/test/resources/projects/basic-resolveDependencies.xml");
146 MavenSession mavenSession = createMavenSession(null);
147 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
148 configuration.setRepositorySession(mavenSession.getRepositorySession());
149 configuration.setResolveDependencies(false);
150
151
152 ProjectBuildingResult result = getContainer()
153 .lookup(org.apache.maven.project.ProjectBuilder.class)
154 .build(pomFile, configuration);
155 assertEquals(0, result.getProject().getArtifacts().size());
156
157 List<ProjectBuildingResult> results = getContainer()
158 .lookup(org.apache.maven.project.ProjectBuilder.class)
159 .build(Collections.singletonList(pomFile), false, configuration);
160 assertEquals(1, results.size());
161 MavenProject mavenProject = results.get(0).getProject();
162 assertEquals(0, mavenProject.getArtifacts().size());
163 }
164
165 @Test
166 void testReadModifiedPoms(@TempDir Path tempDir) throws Exception {
167
168
169
170 FileUtils.copyDirectoryStructure(new File("src/test/resources/projects/grandchild-check"), tempDir.toFile());
171
172 MavenSession mavenSession = createMavenSession(null);
173 mavenSession.getRequest().setRootDirectory(tempDir);
174 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
175 configuration.setRepositorySession(mavenSession.getRepositorySession());
176 org.apache.maven.project.ProjectBuilder projectBuilder =
177 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
178 File child = new File(tempDir.toFile(), "child/pom.xml");
179
180 projectBuilder.build(child, configuration);
181
182 File parent = new File(tempDir.toFile(), "pom.xml");
183 String parentContent = new String(Files.readAllBytes(parent.toPath()), StandardCharsets.UTF_8);
184 parentContent = parentContent.replace(
185 "<packaging>pom</packaging>",
186 "<packaging>pom</packaging><properties><addedProperty>addedValue</addedProperty></properties>");
187 Files.write(parent.toPath(), parentContent.getBytes(StandardCharsets.UTF_8));
188
189 ProjectBuildingResult result = projectBuilder.build(child, configuration);
190 assertTrue(result.getProject().getProperties().containsKey("addedProperty"));
191 }
192
193 @Test
194 void testReadErroneousMavenProjectContainsReference() throws Exception {
195 File pomFile = new File("src/test/resources/projects/artifactMissingVersion/pom.xml").getAbsoluteFile();
196 MavenSession mavenSession = createMavenSession(null);
197 mavenSession.getRequest().setRootDirectory(pomFile.getParentFile().toPath());
198 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
199 configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
200 configuration.setRepositorySession(mavenSession.getRepositorySession());
201 org.apache.maven.project.ProjectBuilder projectBuilder =
202 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
203
204
205 ProjectBuildingException ex1 =
206 assertThrows(ProjectBuildingException.class, () -> projectBuilder.build(pomFile, configuration));
207
208 assertEquals(1, ex1.getResults().size());
209 MavenProject project1 = ex1.getResults().get(0).getProject();
210 assertNotNull(project1);
211 assertEquals("testArtifactMissingVersion", project1.getArtifactId());
212 assertEquals(pomFile, project1.getFile());
213
214
215 ProjectBuildingException ex2 = assertThrows(
216 ProjectBuildingException.class,
217 () -> projectBuilder.build(Collections.singletonList(pomFile), true, configuration));
218
219 assertEquals(1, ex2.getResults().size());
220 MavenProject project2 = ex2.getResults().get(0).getProject();
221 assertNotNull(project2);
222 assertEquals("testArtifactMissingVersion", project2.getArtifactId());
223 assertEquals(pomFile, project2.getFile());
224 }
225
226 @Test
227 void testReadInvalidPom() throws Exception {
228 File pomFile = new File("src/test/resources/projects/badPom.xml").getAbsoluteFile();
229 MavenSession mavenSession = createMavenSession(null);
230 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
231 configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
232 configuration.setRepositorySession(mavenSession.getRepositorySession());
233 org.apache.maven.project.ProjectBuilder projectBuilder =
234 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
235
236
237 Exception ex = assertThrows(Exception.class, () -> projectBuilder.build(pomFile, configuration));
238 assertTrue(ex.getMessage().contains("Received non-all-whitespace CHARACTERS or CDATA event"));
239
240
241 ProjectBuildingException pex = assertThrows(
242 ProjectBuildingException.class,
243 () -> projectBuilder.build(Collections.singletonList(pomFile), false, configuration));
244 assertEquals(1, pex.getResults().size());
245 assertNotNull(pex.getResults().get(0).getPomFile());
246 assertTrue(pex.getResults().get(0).getProblems().size() > 0);
247 ProjectBuildingResultWithProblemMessageAssert.assertThat(
248 pex.getResults().get(0))
249 .hasProblemMessage("Received non-all-whitespace CHARACTERS or CDATA event in nextTag()");
250 }
251
252 @Test
253 void testReadParentAndChildWithRegularVersionSetParentFile() throws Exception {
254 List<File> toRead = new ArrayList<>(2);
255 File parentPom = getProject("MNG-6723");
256 toRead.add(parentPom);
257 toRead.add(new File(parentPom.getParentFile(), "child/pom.xml"));
258 MavenSession mavenSession = createMavenSession(null);
259 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
260 configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
261 configuration.setRepositorySession(mavenSession.getRepositorySession());
262 org.apache.maven.project.ProjectBuilder projectBuilder =
263 getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
264
265
266 boolean parentFileWasFoundOnChild = false;
267 for (File file : toRead) {
268 List<ProjectBuildingResult> results =
269 projectBuilder.build(Collections.singletonList(file), false, configuration);
270 assertResultShowNoError(results);
271 MavenProject project = findChildProject(results);
272 if (project != null) {
273 assertEquals(parentPom, project.getParentFile());
274 parentFileWasFoundOnChild = true;
275 }
276 }
277 assertTrue(parentFileWasFoundOnChild);
278
279
280 List<ProjectBuildingResult> results = projectBuilder.build(toRead, false, configuration);
281 assertResultShowNoError(results);
282 assertEquals(parentPom, findChildProject(results).getParentFile());
283 Collections.reverse(toRead);
284 results = projectBuilder.build(toRead, false, configuration);
285 assertResultShowNoError(results);
286 assertEquals(parentPom, findChildProject(results).getParentFile());
287 }
288
289 private MavenProject findChildProject(List<ProjectBuildingResult> results) {
290 for (ProjectBuildingResult result : results) {
291 if (result.getPomFile().getParentFile().getName().equals("child")) {
292 return result.getProject();
293 }
294 }
295 return null;
296 }
297
298 private void assertResultShowNoError(List<ProjectBuildingResult> results) {
299 for (ProjectBuildingResult result : results) {
300 assertTrue(result.getProblems().isEmpty());
301 assertNotNull(result.getProject());
302 }
303 }
304
305 @Test
306 void testBuildProperties() throws Exception {
307 File file = new File(getProject("MNG-6716").getParentFile(), "project/pom.xml");
308 MavenSession mavenSession = createMavenSession(null);
309 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
310 configuration.setRepositorySession(mavenSession.getRepositorySession());
311 configuration.setResolveDependencies(true);
312 List<ProjectBuildingResult> result =
313 projectBuilder.build(Collections.singletonList(file), false, configuration);
314 MavenProject project = result.get(0).getProject();
315
316 assertEquals(1, project.getTestCompileSourceRoots().size());
317 assertEquals(1, project.getCompileSourceRoots().size());
318 assertEquals(1, project.getMailingLists().size());
319 assertEquals(1, project.getResources().size());
320 }
321
322 @Test
323 void testPropertyInPluginManagementGroupId() throws Exception {
324 File pom = getProject("MNG-6983");
325
326 MavenSession session = createMavenSession(pom);
327 MavenProject project = session.getCurrentProject();
328
329 for (Plugin buildPlugin : project.getBuildPlugins()) {
330 assertNotNull(buildPlugin.getVersion(), "Missing version for build plugin " + buildPlugin.getKey());
331 }
332 }
333
334 @Test
335 void testBuildFromModelSourceResolvesBasedir() throws Exception {
336 File pomFile = new File("src/test/resources/projects/modelsourcebasedir/pom.xml");
337 MavenSession mavenSession = createMavenSession(null);
338 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
339 configuration.setRepositorySession(mavenSession.getRepositorySession());
340 ProjectBuildingResult result = getContainer()
341 .lookup(org.apache.maven.project.ProjectBuilder.class)
342 .build(pomFile, configuration);
343
344 assertEquals(
345 pomFile.getAbsoluteFile(),
346 result.getProject().getModel().getPomFile().getAbsoluteFile());
347 int errors = 0;
348 for (ModelProblem p : result.getProblems()) {
349 if (p.getSeverity() == ModelProblem.Severity.ERROR) {
350 errors++;
351 }
352 }
353 assertEquals(0, errors);
354 }
355
356 @Test
357 void testLocationTrackingResolution() throws Exception {
358 File pom = getProject("MNG-7648");
359
360 MavenSession session = createMavenSession(pom);
361 MavenProject project = session.getCurrentProject();
362
363 InputLocation dependencyLocation = null;
364 for (Dependency dependency : project.getDependencies()) {
365 if (dependency.getManagementKey().equals("org.apache.maven.its:a:jar")) {
366 dependencyLocation = dependency.getLocation("version");
367 }
368 }
369 assertNotNull(dependencyLocation, "missing dependency");
370 assertEquals(
371 "org.apache.maven.its:bom:0.1", dependencyLocation.getSource().getModelId());
372
373 InputLocation pluginLocation = null;
374 for (Plugin plugin : project.getBuildPlugins()) {
375 if (plugin.getKey().equals("org.apache.maven.plugins:maven-clean-plugin")) {
376 pluginLocation = plugin.getLocation("version");
377 }
378 }
379 assertNotNull(pluginLocation, "missing build plugin");
380 assertEquals(
381 "org.apache.maven.its:parent:0.1", pluginLocation.getSource().getModelId());
382 }
383
384
385
386
387
388
389
390
391 @Test
392 void testModularSourcesInjectResourceRoots() throws Exception {
393 File pom = getProject("modular-sources");
394
395 MavenSession session = createMavenSession(pom);
396 MavenProject project = session.getCurrentProject();
397
398
399 List<SourceRoot> mainResourceRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)
400 .toList();
401
402
403 Set<String> modules = mainResourceRoots.stream()
404 .map(SourceRoot::module)
405 .flatMap(Optional::stream)
406 .collect(Collectors.toSet());
407
408 assertEquals(2, modules.size(), "Should have resource roots for 2 modules");
409 assertTrue(modules.contains("org.foo.moduleA"), "Should have resource root for moduleA");
410 assertTrue(modules.contains("org.foo.moduleB"), "Should have resource root for moduleB");
411
412
413 List<SourceRoot> testResourceRoots = project.getEnabledSourceRoots(ProjectScope.TEST, Language.RESOURCES)
414 .toList();
415
416
417 Set<String> testModules = testResourceRoots.stream()
418 .map(SourceRoot::module)
419 .flatMap(Optional::stream)
420 .collect(Collectors.toSet());
421
422 assertEquals(2, testModules.size(), "Should have test resource roots for 2 modules");
423 assertTrue(testModules.contains("org.foo.moduleA"), "Should have test resource root for moduleA");
424 assertTrue(testModules.contains("org.foo.moduleB"), "Should have test resource root for moduleB");
425 }
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 @Test
442 void testModularSourcesWithExplicitResourcesIssuesError() throws Exception {
443 File pom = getProject("modular-sources-with-explicit-resources");
444
445 MavenSession mavenSession = createMavenSession(null);
446 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
447 configuration.setRepositorySession(mavenSession.getRepositorySession());
448
449 ProjectBuildingResult result = getContainer()
450 .lookup(org.apache.maven.project.ProjectBuilder.class)
451 .build(pom, configuration);
452
453 MavenProject project = result.getProject();
454
455
456 List<ModelProblem> errors = result.getProblems().stream()
457 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
458 .filter(p -> p.getMessage().contains("Legacy") && p.getMessage().contains("cannot be used"))
459 .toList();
460
461 assertEquals(2, errors.size(), "Should have 2 errors (one for resources, one for testResources)");
462 assertTrue(
463 errors.stream().anyMatch(e -> e.getMessage().contains("<resources>")),
464 "Should error about conflicting <resources>");
465 assertTrue(
466 errors.stream().anyMatch(e -> e.getMessage().contains("<testResources>")),
467 "Should error about conflicting <testResources>");
468
469
470 List<SourceRoot> mainResourceRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)
471 .toList();
472
473 assertEquals(2, mainResourceRoots.size(), "Should have 2 modular resource roots (one per module)");
474
475 Set<String> mainModules = mainResourceRoots.stream()
476 .map(SourceRoot::module)
477 .flatMap(Optional::stream)
478 .collect(Collectors.toSet());
479
480 assertEquals(2, mainModules.size(), "Should have resource roots for 2 modules");
481 assertTrue(mainModules.contains("org.foo.moduleA"), "Should have resource root for moduleA");
482 assertTrue(mainModules.contains("org.foo.moduleB"), "Should have resource root for moduleB");
483 }
484
485
486
487
488
489
490
491
492
493
494
495 @Test
496 void testModularWithJavaSourcesRejectsLegacySourceDirectory() throws Exception {
497 File pom = getProject("modular-java-with-explicit-source-dir");
498
499 MavenSession mavenSession = createMavenSession(null);
500 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
501 configuration.setRepositorySession(mavenSession.getRepositorySession());
502
503 ProjectBuildingResult result = getContainer()
504 .lookup(org.apache.maven.project.ProjectBuilder.class)
505 .build(pom, configuration);
506
507 MavenProject project = result.getProject();
508
509
510 List<ModelProblem> errors = result.getProblems().stream()
511 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
512 .filter(p -> p.getMessage().contains("Legacy") && p.getMessage().contains("cannot be used"))
513 .filter(p -> p.getMessage().contains("<sourceDirectory>"))
514 .toList();
515
516 assertEquals(1, errors.size(), "Should have 1 error for <sourceDirectory>");
517
518
519 List<SourceRoot> mainJavaRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)
520 .toList();
521 assertEquals(1, mainJavaRoots.size(), "Should have 1 modular main Java source root");
522 assertEquals("org.foo.app", mainJavaRoots.get(0).module().orElse(null), "Should have module org.foo.app");
523
524
525 assertFalse(
526 mainJavaRoots.get(0).directory().toString().contains("src/custom/main/java"),
527 "Legacy sourceDirectory should not be used");
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541 @Test
542 void testModularWithoutTestSourcesRejectsLegacyTestSourceDirectory() throws Exception {
543 File pom = getProject("modular-no-test-java-with-explicit-test-source-dir");
544
545 MavenSession mavenSession = createMavenSession(null);
546 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
547 configuration.setRepositorySession(mavenSession.getRepositorySession());
548
549 ProjectBuildingResult result = getContainer()
550 .lookup(org.apache.maven.project.ProjectBuilder.class)
551 .build(pom, configuration);
552
553 MavenProject project = result.getProject();
554
555
556 List<ModelProblem> errors = result.getProblems().stream()
557 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
558 .filter(p -> p.getMessage().contains("Legacy") && p.getMessage().contains("cannot be used"))
559 .filter(p -> p.getMessage().contains("<testSourceDirectory>"))
560 .toList();
561
562 assertEquals(1, errors.size(), "Should have 1 error for <testSourceDirectory>");
563
564
565 List<SourceRoot> testJavaRoots = project.getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)
566 .toList();
567 assertEquals(0, testJavaRoots.size(), "Should have no test Java sources");
568 }
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583 @Test
584 void testClassicSourcesWithExplicitLegacyDirectories() throws Exception {
585 File pom = getProject("classic-sources-with-explicit-legacy");
586
587 MavenSession mavenSession = createMavenSession(null);
588 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
589 configuration.setRepositorySession(mavenSession.getRepositorySession());
590
591 ProjectBuildingResult result = getContainer()
592 .lookup(org.apache.maven.project.ProjectBuilder.class)
593 .build(pom, configuration);
594
595
596 List<ModelProblem> errors = result.getProblems().stream()
597 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
598 .filter(p -> p.getMessage().contains("Legacy") && p.getMessage().contains("cannot be used"))
599 .toList();
600
601 assertEquals(2, errors.size(), "Should have 2 errors (one for sourceDirectory, one for testSourceDirectory)");
602
603
604 assertTrue(
605 errors.stream().anyMatch(e -> e.getMessage().contains("<sourceDirectory>")),
606 "Should have error for <sourceDirectory>");
607 assertTrue(
608 errors.stream().anyMatch(e -> e.getMessage().contains("<testSourceDirectory>")),
609 "Should have error for <testSourceDirectory>");
610 }
611
612
613
614
615
616
617
618
619
620
621
622 @Test
623 void testNonModularResourcesOnlyWithImplicitJavaFallback() throws Exception {
624 File pom = getProject("non-modular-resources-only");
625
626 MavenSession mavenSession = createMavenSession(null);
627 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
628 configuration.setRepositorySession(mavenSession.getRepositorySession());
629
630 ProjectBuildingResult result = getContainer()
631 .lookup(org.apache.maven.project.ProjectBuilder.class)
632 .build(pom, configuration);
633
634 MavenProject project = result.getProject();
635
636
637 List<ModelProblem> errors = result.getProblems().stream()
638 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
639 .filter(p -> p.getMessage().contains("Legacy") && p.getMessage().contains("cannot be used"))
640 .toList();
641
642 assertEquals(0, errors.size(), "Should have no errors - legacy directories used as fallback (AC9)");
643
644
645 List<SourceRoot> mainResources = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)
646 .toList();
647 assertTrue(
648 mainResources.stream()
649 .anyMatch(sr -> sr.directory()
650 .toString()
651 .replace(File.separatorChar, '/')
652 .contains("src/main/custom-resources")),
653 "Should have custom main resources from <sources>");
654
655
656 List<SourceRoot> mainJavaRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)
657 .toList();
658 assertEquals(1, mainJavaRoots.size(), "Should have 1 main Java source (implicit fallback)");
659 assertTrue(
660 mainJavaRoots
661 .get(0)
662 .directory()
663 .toString()
664 .replace(File.separatorChar, '/')
665 .endsWith("src/main/java"),
666 "Should use default src/main/java as fallback");
667
668 List<SourceRoot> testJavaRoots = project.getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)
669 .toList();
670 assertEquals(1, testJavaRoots.size(), "Should have 1 test Java source (implicit fallback)");
671 assertTrue(
672 testJavaRoots
673 .get(0)
674 .directory()
675 .toString()
676 .replace(File.separatorChar, '/')
677 .endsWith("src/test/java"),
678 "Should use default src/test/java as fallback");
679 }
680
681
682
683
684
685
686
687
688
689
690 @Test
691 void testNonModularResourcesOnlyWithExplicitLegacyDirectoriesRejected() throws Exception {
692 File pom = getProject("non-modular-resources-only-explicit-legacy");
693
694 MavenSession mavenSession = createMavenSession(null);
695 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
696 configuration.setRepositorySession(mavenSession.getRepositorySession());
697
698 ProjectBuildingResult result = getContainer()
699 .lookup(org.apache.maven.project.ProjectBuilder.class)
700 .build(pom, configuration);
701
702 MavenProject project = result.getProject();
703
704
705 List<ModelProblem> errors = result.getProblems().stream()
706 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
707 .filter(p -> p.getMessage().contains("Legacy") && p.getMessage().contains("cannot be used"))
708 .toList();
709
710 assertEquals(2, errors.size(), "Should have 2 errors for explicit legacy directories");
711 assertTrue(
712 errors.stream().anyMatch(e -> e.getMessage().contains("<sourceDirectory>")),
713 "Should error about <sourceDirectory>");
714 assertTrue(
715 errors.stream().anyMatch(e -> e.getMessage().contains("<testSourceDirectory>")),
716 "Should error about <testSourceDirectory>");
717
718
719 List<SourceRoot> mainResources = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)
720 .toList();
721 assertTrue(
722 mainResources.stream()
723 .anyMatch(sr -> sr.directory()
724 .toString()
725 .replace(File.separatorChar, '/')
726 .contains("src/main/custom-resources")),
727 "Should have custom main resources from <sources>");
728
729
730 List<SourceRoot> mainJavaRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)
731 .toList();
732 assertEquals(0, mainJavaRoots.size(), "Should have no main Java sources (legacy rejected)");
733
734 List<SourceRoot> testJavaRoots = project.getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)
735 .toList();
736 assertEquals(0, testJavaRoots.size(), "Should have no test Java sources (legacy rejected)");
737 }
738
739
740
741
742
743
744
745
746
747
748
749 @Test
750 void testModularWithPhysicalDefaultLegacyDirectory() throws Exception {
751 File pom = getProject("modular-with-physical-legacy");
752
753 MavenSession mavenSession = createMavenSession(null);
754 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
755 configuration.setRepositorySession(mavenSession.getRepositorySession());
756
757 ProjectBuildingResult result = getContainer()
758 .lookup(org.apache.maven.project.ProjectBuilder.class)
759 .build(pom, configuration);
760
761
762 List<ModelProblem> errors = result.getProblems().stream()
763 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
764 .filter(p -> p.getMessage().contains("Legacy directory")
765 && p.getMessage().contains("exists"))
766 .toList();
767
768
769 assertEquals(2, errors.size(), "Should have 2 errors for physical legacy directories");
770
771 String mainJava = "src" + File.separator + "main" + File.separator + "java";
772 String testJava = "src" + File.separator + "test" + File.separator + "java";
773 assertTrue(
774 errors.stream().anyMatch(e -> e.getMessage().contains(mainJava)),
775 "Should error about physical src/main/java");
776 assertTrue(
777 errors.stream().anyMatch(e -> e.getMessage().contains(testJava)),
778 "Should error about physical src/test/java");
779 }
780
781
782
783
784
785
786
787
788
789
790 @Test
791 void testModularResourcesOnlyWithPhysicalDefaultLegacyDirectory() throws Exception {
792 File pom = getProject("modular-resources-only-with-physical-legacy");
793
794 MavenSession mavenSession = createMavenSession(null);
795 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
796 configuration.setRepositorySession(mavenSession.getRepositorySession());
797
798 ProjectBuildingResult result = getContainer()
799 .lookup(org.apache.maven.project.ProjectBuilder.class)
800 .build(pom, configuration);
801
802
803
804 List<ModelProblem> errors = result.getProblems().stream()
805 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
806 .filter(p -> p.getMessage().contains("Legacy directory")
807 && p.getMessage().contains("exists"))
808 .toList();
809
810
811 assertEquals(
812 2, errors.size(), "Should have 2 errors for physical legacy directories (no AC9 fallback for modular)");
813
814 String mainJava = "src" + File.separator + "main" + File.separator + "java";
815 String testJava = "src" + File.separator + "test" + File.separator + "java";
816 assertTrue(
817 errors.stream().anyMatch(e -> e.getMessage().contains(mainJava)),
818 "Should error about physical src/main/java");
819 assertTrue(
820 errors.stream().anyMatch(e -> e.getMessage().contains(testJava)),
821 "Should error about physical src/test/java");
822 }
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842 @Test
843 void testSourcesMixedModulesWithinSources() throws Exception {
844 File pom = getProject("sources-mixed-modules");
845
846 MavenSession mavenSession = createMavenSession(null);
847 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
848 configuration.setRepositorySession(mavenSession.getRepositorySession());
849
850 ProjectBuildingResult result = getContainer()
851 .lookup(org.apache.maven.project.ProjectBuilder.class)
852 .build(pom, configuration);
853
854
855 List<ModelProblem> errors = result.getProblems().stream()
856 .filter(p -> p.getSeverity() == ModelProblem.Severity.ERROR)
857 .filter(p -> p.getMessage().contains("Mixed modular and classic sources"))
858 .toList();
859
860 assertEquals(1, errors.size(), "Should have 1 error for mixed modular/classic configuration");
861 assertTrue(errors.get(0).getMessage().contains("lang=java"), "Error should mention java language");
862 assertTrue(errors.get(0).getMessage().contains("scope=main"), "Error should mention main scope");
863 }
864
865
866
867
868
869
870
871
872
873
874
875
876 @Test
877 void testMultipleDirectoriesSameModule() throws Exception {
878 File pom = getProject("multiple-directories-same-module");
879
880 MavenSession session = createMavenSession(pom);
881 MavenProject project = session.getCurrentProject();
882
883
884 List<SourceRoot> mainJavaRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)
885 .toList();
886
887
888 assertEquals(2, mainJavaRoots.size(), "Should have 2 main Java source roots for same module");
889
890
891 long moduleCount = mainJavaRoots.stream()
892 .filter(sr -> "com.example.app".equals(sr.module().orElse(null)))
893 .count();
894 assertEquals(2, moduleCount, "Both main sources should be for com.example.app module");
895
896
897 boolean hasImplicitDir = mainJavaRoots.stream()
898 .anyMatch(sr -> sr.directory()
899 .toString()
900 .replace(File.separatorChar, '/')
901 .contains("src/com.example.app/main/java"));
902 boolean hasGeneratedDir = mainJavaRoots.stream()
903 .anyMatch(sr -> sr.directory()
904 .toString()
905 .replace(File.separatorChar, '/')
906 .contains("target/generated-sources/com.example.app/java"));
907
908 assertTrue(hasImplicitDir, "Should have implicit source directory for module");
909 assertTrue(hasGeneratedDir, "Should have generated-sources directory for module");
910
911
912 List<SourceRoot> testJavaRoots = project.getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)
913 .toList();
914
915
916 assertEquals(2, testJavaRoots.size(), "Should have 2 test Java source roots for same module");
917
918
919 long testModuleCount = testJavaRoots.stream()
920 .filter(sr -> "com.example.app".equals(sr.module().orElse(null)))
921 .count();
922 assertEquals(2, testModuleCount, "Both test sources should be for com.example.app module");
923 }
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945 @Test
946 void testDuplicateEnabledSources() throws Exception {
947 File pom = getProject("duplicate-enabled-sources");
948
949 MavenSession mavenSession = createMavenSession(null);
950 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
951 configuration.setRepositorySession(mavenSession.getRepositorySession());
952
953 ProjectBuildingResult result = getContainer()
954 .lookup(org.apache.maven.project.ProjectBuilder.class)
955 .build(pom, configuration);
956
957 MavenProject project = result.getProject();
958
959
960 List<ModelProblem> duplicateWarnings = result.getProblems().stream()
961 .filter(p -> p.getSeverity() == ModelProblem.Severity.WARNING)
962 .filter(p -> p.getMessage().contains("Duplicate enabled source"))
963 .toList();
964
965
966 assertEquals(2, duplicateWarnings.size(), "Should have 2 duplicate warnings (main and test scope)");
967
968
969 List<SourceRoot> mainJavaRoots = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.JAVA_FAMILY)
970 .toList();
971
972
973
974 assertEquals(2, mainJavaRoots.size(), "Should have 2 main Java source roots");
975
976
977 boolean hasOtherModule = mainJavaRoots.stream()
978 .anyMatch(sr -> "com.example.other".equals(sr.module().orElse(null)));
979 assertTrue(hasOtherModule, "Should have source root for com.example.other module");
980
981
982 boolean hasDupModule = mainJavaRoots.stream()
983 .anyMatch(sr -> "com.example.dup".equals(sr.module().orElse(null)));
984 assertTrue(hasDupModule, "Should have source root for com.example.dup module");
985
986
987 List<SourceRoot> testJavaRoots = project.getEnabledSourceRoots(ProjectScope.TEST, Language.JAVA_FAMILY)
988 .toList();
989
990
991 assertEquals(1, testJavaRoots.size(), "Should have 1 test Java source root");
992
993
994 assertEquals(
995 "com.example.dup",
996 testJavaRoots.get(0).module().orElse(null),
997 "Test source root should be for com.example.dup module");
998 }
999
1000 @Test
1001 void testResourceTargetPathRemainsRelativeInCompatLayer() throws Exception {
1002 File pom = getProject("resource-target-path");
1003
1004 MavenSession mavenSession = createMavenSession(null);
1005 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
1006 configuration.setRepositorySession(mavenSession.getRepositorySession());
1007
1008 ProjectBuildingResult result = getContainer()
1009 .lookup(org.apache.maven.project.ProjectBuilder.class)
1010 .build(pom, configuration);
1011
1012 MavenProject project = result.getProject();
1013
1014
1015 List<SourceRoot> mainResources = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)
1016 .toList();
1017 assertEquals(1, mainResources.size());
1018 assertTrue(mainResources.get(0).targetPath().isPresent(), "Main resource should have a targetPath");
1019 assertFalse(
1020 mainResources.get(0).targetPath().get().isAbsolute(),
1021 "SourceRoot targetPath must be relative, got: "
1022 + mainResources.get(0).targetPath().get());
1023 assertEquals(
1024 Path.of("META-INF/tags/rdc"), mainResources.get(0).targetPath().get());
1025
1026
1027 List<SourceRoot> testResources = project.getEnabledSourceRoots(ProjectScope.TEST, Language.RESOURCES)
1028 .toList();
1029 assertEquals(1, testResources.size());
1030 assertTrue(testResources.get(0).targetPath().isPresent(), "Test resource should have a targetPath");
1031 assertFalse(
1032 testResources.get(0).targetPath().get().isAbsolute(),
1033 "SourceRoot targetPath must be relative, got: "
1034 + testResources.get(0).targetPath().get());
1035 assertEquals(
1036 Path.of("org/apache/maven/messages"),
1037 testResources.get(0).targetPath().get());
1038
1039
1040 List<org.apache.maven.model.Resource> resources = project.getResources();
1041 assertEquals(1, resources.size());
1042 assertEquals(
1043 "META-INF" + File.separator + "tags" + File.separator + "rdc",
1044 resources.get(0).getTargetPath(),
1045 "Resource targetPath from getResources() must remain relative");
1046
1047
1048 List<org.apache.maven.model.Resource> testResourceList = project.getTestResources();
1049 assertEquals(1, testResourceList.size());
1050 assertEquals(
1051 "org" + File.separator + "apache" + File.separator + "maven" + File.separator + "messages",
1052 testResourceList.get(0).getTargetPath(),
1053 "Test resource targetPath from getTestResources() must remain relative");
1054 }
1055
1056 @Test
1057 void testSourceTargetPathRemainsRelative() throws Exception {
1058 File pom = getProject("source-target-path");
1059
1060 MavenSession mavenSession = createMavenSession(null);
1061 ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
1062 configuration.setRepositorySession(mavenSession.getRepositorySession());
1063
1064 ProjectBuildingResult result = getContainer()
1065 .lookup(org.apache.maven.project.ProjectBuilder.class)
1066 .build(pom, configuration);
1067
1068 MavenProject project = result.getProject();
1069
1070
1071 List<SourceRoot> mainResources = project.getEnabledSourceRoots(ProjectScope.MAIN, Language.RESOURCES)
1072 .toList();
1073 assertEquals(1, mainResources.size());
1074 assertTrue(mainResources.get(0).targetPath().isPresent());
1075 assertEquals(Path.of(".grammar"), mainResources.get(0).targetPath().get());
1076
1077
1078 List<SourceRoot> testResources = project.getEnabledSourceRoots(ProjectScope.TEST, Language.RESOURCES)
1079 .toList();
1080 assertEquals(1, testResources.size());
1081 assertTrue(testResources.get(0).targetPath().isPresent());
1082 assertEquals(Path.of("META-INF/test"), testResources.get(0).targetPath().get());
1083
1084
1085 List<org.apache.maven.model.Resource> resources = project.getResources();
1086 assertEquals(1, resources.size());
1087 assertEquals(".grammar", resources.get(0).getTargetPath());
1088
1089 List<org.apache.maven.model.Resource> testResourceList = project.getTestResources();
1090 assertEquals(1, testResourceList.size());
1091 assertEquals(
1092 "META-INF" + File.separator + "test", testResourceList.get(0).getTargetPath());
1093 }
1094 }