|
24 | 24 |
|
25 | 25 | import java.io.IOException;
|
26 | 26 | import java.io.InputStream;
|
27 |
| -import java.io.UncheckedIOException; |
28 | 27 | import java.io.Writer;
|
29 | 28 | import java.lang.module.ModuleDescriptor;
|
30 |
| -import java.nio.file.FileVisitResult; |
31 | 29 | import java.nio.file.Files;
|
32 | 30 | import java.nio.file.Path;
|
33 |
| -import java.nio.file.SimpleFileVisitor; |
34 |
| -import java.nio.file.attribute.BasicFileAttributes; |
35 | 31 | import java.util.ArrayList;
|
36 | 32 | import java.util.HashSet;
|
37 | 33 | import java.util.LinkedHashMap;
|
|
40 | 36 | import java.util.Map;
|
41 | 37 | import java.util.Set;
|
42 | 38 | import java.util.StringJoiner;
|
43 |
| -import java.util.stream.Stream; |
44 | 39 |
|
45 | 40 | import org.apache.maven.api.Dependency;
|
46 | 41 | import org.apache.maven.api.JavaPathType;
|
@@ -86,6 +81,13 @@ class ToolExecutorForTest extends ToolExecutor {
|
86 | 81 | */
|
87 | 82 | private final boolean hasTestModuleInfo;
|
88 | 83 |
|
| 84 | + /** |
| 85 | + * Whether the tests are declared in their own module. If {@code true}, |
| 86 | + * then the {@code module-info.java} file of the test declares a name |
| 87 | + * different than the {@code module-info.java} file of the main code. |
| 88 | + */ |
| 89 | + private boolean testInItsOwnModule; |
| 90 | + |
89 | 91 | /**
|
90 | 92 | * Whether the {@code module-info} of the tests overwrites the main {@code module-info}.
|
91 | 93 | * This is a deprecated practice, but is accepted if {@link #SUPPORT_LEGACY} is true.
|
@@ -154,6 +156,7 @@ class ToolExecutorForTest extends ToolExecutor {
|
154 | 156 | if (testModuleName != null) {
|
155 | 157 | overwriteMainModuleInfo = testModuleName.equals(getMainModuleName());
|
156 | 158 | if (!overwriteMainModuleInfo) {
|
| 159 | + testInItsOwnModule = true; |
157 | 160 | continue; // The test classes are in their own module.
|
158 | 161 | }
|
159 | 162 | }
|
@@ -191,10 +194,12 @@ class ToolExecutorForTest extends ToolExecutor {
|
191 | 194 | PathType pathType = JavaPathType.CLASSES;
|
192 | 195 | if (hasModuleDeclaration) {
|
193 | 196 | pathType = JavaPathType.MODULES;
|
194 |
| - String moduleToPatch = getMainModuleName(); |
195 |
| - if (!moduleToPatch.isEmpty()) { |
196 |
| - pathType = JavaPathType.patchModule(moduleToPatch); |
197 |
| - directoryLevelToRemove = outputDirectory.resolve(moduleToPatch); |
| 197 | + if (!testInItsOwnModule) { |
| 198 | + String moduleToPatch = getMainModuleName(); |
| 199 | + if (!moduleToPatch.isEmpty()) { |
| 200 | + pathType = JavaPathType.patchModule(moduleToPatch); |
| 201 | + directoryLevelToRemove = outputDirectory.resolve(moduleToPatch); |
| 202 | + } |
198 | 203 | }
|
199 | 204 | }
|
200 | 205 | dependencies.computeIfAbsent(pathType, (key) -> new ArrayList<>()).add(0, mainOutputDirectory);
|
@@ -226,7 +231,7 @@ private String getMainModuleName() throws IOException {
|
226 | 231 | */
|
227 | 232 | @Override
|
228 | 233 | final String inferModuleNameIfMissing(String moduleName) throws IOException {
|
229 |
| - return moduleName.isEmpty() ? getMainModuleName() : moduleName; |
| 234 | + return (!testInItsOwnModule && moduleName.isEmpty()) ? getMainModuleName() : moduleName; |
230 | 235 | }
|
231 | 236 |
|
232 | 237 | /**
|
@@ -334,53 +339,19 @@ public boolean applyIncrementalBuild(AbstractCompilerMojo mojo, Options configur
|
334 | 339 | @Override
|
335 | 340 | public boolean compile(JavaCompiler compiler, Options configuration, Writer otherOutput) throws IOException {
|
336 | 341 | addModuleOptions(configuration); // Effective only once.
|
| 342 | + Path delete = null; |
337 | 343 | try {
|
| 344 | + if (directoryLevelToRemove != null) { |
| 345 | + delete = Files.createSymbolicLink(directoryLevelToRemove, directoryLevelToRemove.getParent()); |
| 346 | + } |
338 | 347 | return super.compile(compiler, configuration, otherOutput);
|
339 | 348 | } finally {
|
340 |
| - if (directoryLevelToRemove != null && Files.exists(directoryLevelToRemove)) { |
341 |
| - Path target = directoryLevelToRemove.getParent(); |
342 |
| - try (Stream<Path> files = Files.list(directoryLevelToRemove)) { |
343 |
| - files.forEach((path) -> { |
344 |
| - try { |
345 |
| - Files.move(path, deleteRecursively(target.resolve(path.getFileName()))); |
346 |
| - } catch (IOException e) { |
347 |
| - throw new UncheckedIOException(e); |
348 |
| - } |
349 |
| - }); |
350 |
| - } catch (UncheckedIOException e) { |
351 |
| - throw e.getCause(); |
352 |
| - } |
353 |
| - Files.delete(directoryLevelToRemove); |
| 349 | + if (delete != null) { |
| 350 | + Files.delete(delete); |
354 | 351 | }
|
355 | 352 | }
|
356 | 353 | }
|
357 | 354 |
|
358 |
| - /** |
359 |
| - * Deletes the specified directory recursively. |
360 |
| - * |
361 |
| - * @param delete the directory to delete |
362 |
| - * @return the given directory |
363 |
| - */ |
364 |
| - private static Path deleteRecursively(Path delete) throws IOException { |
365 |
| - if (Files.notExists(delete)) { |
366 |
| - return delete; |
367 |
| - } |
368 |
| - return Files.walkFileTree(delete, new SimpleFileVisitor<Path>() { |
369 |
| - @Override |
370 |
| - public FileVisitResult postVisitDirectory(Path dir, IOException error) throws IOException { |
371 |
| - var result = super.postVisitDirectory(dir, error); |
372 |
| - Files.delete(dir); |
373 |
| - return result; |
374 |
| - } |
375 |
| - |
376 |
| - @Override |
377 |
| - public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException { |
378 |
| - Files.delete(file); |
379 |
| - return super.visitFile(file, attributes); |
380 |
| - } |
381 |
| - }); |
382 |
| - } |
383 |
| - |
384 | 355 | /**
|
385 | 356 | * Separates the compilation of {@code module-info} from other classes. This is needed when the
|
386 | 357 | * {@code module-info} of the test classes overwrite the {@code module-info} of the main classes.
|
|
0 commit comments