|
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