1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8173777 27 * @summary tests for multi-module mode compilation 28 * @library /tools/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.code 32 * jdk.compiler/com.sun.tools.javac.main 33 * jdk.compiler/com.sun.tools.javac.processing 34 * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase 35 * @run main XModuleTest 36 */ 37 38 import java.nio.file.Files; 39 import java.nio.file.Path; 40 import java.util.Arrays; 41 import java.util.List; 42 import java.util.Set; 43 import java.util.stream.Collectors; 44 45 import javax.annotation.processing.AbstractProcessor; 46 import javax.annotation.processing.RoundEnvironment; 47 import javax.annotation.processing.SupportedAnnotationTypes; 48 import javax.lang.model.SourceVersion; 49 import javax.lang.model.element.ModuleElement; 50 import javax.lang.model.element.TypeElement; 51 import javax.lang.model.util.Elements; 52 53 import com.sun.tools.javac.code.Symtab; 54 import com.sun.tools.javac.processing.JavacProcessingEnvironment; 55 import toolbox.JavacTask; 56 import toolbox.ModuleBuilder; 57 import toolbox.Task; 58 import toolbox.Task.Expect; 59 60 public class XModuleTest extends ModuleTestBase { 61 62 public static void main(String... args) throws Exception { 63 new XModuleTest().runTests(); 64 } 65 66 @Test 67 public void testCorrectXModule(Path base) throws Exception { 68 //note: avoiding use of java.base, as that gets special handling on some places: 69 Path src = base.resolve("src"); 70 tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }"); 71 Path classes = base.resolve("classes"); 72 tb.createDirectories(classes); 73 74 String log = new JavacTask(tb) 75 .options("--patch-module", "java.compiler=" + src.toString()) 76 .outdir(classes) 77 .files(findJavaFiles(src)) 78 .run() 79 .writeAll() 80 .getOutput(Task.OutputKind.DIRECT); 81 82 if (!log.isEmpty()) 83 throw new Exception("expected output not found: " + log); 84 } 85 86 @Test 87 public void testCorrectXModuleMultiModule(Path base) throws Exception { 88 //note: avoiding use of java.base, as that gets special handling on some places: 89 Path src = base.resolve("src"); 90 Path m1 = src.resolve("m1"); 91 tb.writeJavaFiles(m1, "package javax.lang.model.element; public interface Extra extends Element { }"); 92 Path m2 = src.resolve("m2"); 93 tb.writeJavaFiles(m2, "package com.sun.source.tree; public interface Extra extends Tree { }"); 94 Path classes = base.resolve("classes"); 95 tb.createDirectories(classes); 96 97 String log = new JavacTask(tb) 98 .options("--patch-module", "java.compiler=" + m1.toString(), 99 "--patch-module", "jdk.compiler=" + m2.toString(), 100 "--module-source-path", "dummy") 101 .outdir(classes) 102 .files(findJavaFiles(src)) 103 .run() 104 .writeAll() 105 .getOutput(Task.OutputKind.DIRECT); 106 107 if (!log.isEmpty()) 108 throw new Exception("expected output not found: " + log); 109 110 checkFileExists(classes, "java.compiler/javax/lang/model/element/Extra.class"); 111 checkFileExists(classes, "jdk.compiler/com/sun/source/tree/Extra.class"); 112 } 113 114 @Test 115 public void testCorrectXModuleMultiModule2(Path base) throws Exception { 116 //note: avoiding use of java.base, as that gets special handling on some places: 117 Path src = base.resolve("src"); 118 Path m1 = src.resolve("m1"); 119 tb.writeJavaFiles(m1, 120 "package javax.lang.model.element; public interface Extra extends Element { }"); 121 Path m2 = src.resolve("m2"); 122 tb.writeJavaFiles(m2, 123 "package com.sun.source.tree; public interface Extra extends Tree { }"); 124 Path msp = base.resolve("msp"); 125 Path m3 = msp.resolve("m3x"); 126 tb.writeJavaFiles(m3, 127 "module m3x { }", 128 "package m3; public class Test { }"); 129 Path m4 = msp.resolve("m4x"); 130 tb.writeJavaFiles(m4, 131 "module m4x { }", 132 "package m4; public class Test { }"); 133 Path classes = base.resolve("classes"); 134 tb.createDirectories(classes); 135 136 String log = new JavacTask(tb) 137 .options("--patch-module", "java.compiler=" + m1.toString(), 138 "--patch-module", "jdk.compiler=" + m2.toString(), 139 "--module-source-path", msp.toString()) 140 .outdir(classes) 141 .files(findJavaFiles(src, msp)) 142 .run() 143 .writeAll() 144 .getOutput(Task.OutputKind.DIRECT); 145 146 if (!log.isEmpty()) 147 throw new Exception("expected output not found: " + log); 148 149 checkFileExists(classes, "java.compiler/javax/lang/model/element/Extra.class"); 150 checkFileExists(classes, "jdk.compiler/com/sun/source/tree/Extra.class"); 151 checkFileExists(classes, "m3x/m3/Test.class"); 152 checkFileExists(classes, "m4x/m4/Test.class"); 153 } 154 155 @Test 156 public void testPatchModuleModuleSourcePathConflict(Path base) throws Exception { 157 //note: avoiding use of java.base, as that gets special handling on some places: 158 Path src = base.resolve("src"); 159 Path m1 = src.resolve("m1x"); 160 tb.writeJavaFiles(m1, 161 "module m1x { }", 162 "package m1; public class Test { }"); 163 Path m2 = src.resolve("m2x"); 164 tb.writeJavaFiles(m2, 165 "module m2x { }", 166 "package m2; public class Test { }"); 167 Path classes = base.resolve("classes"); 168 tb.createDirectories(classes); 169 170 List<String> log = new JavacTask(tb) 171 .options("--patch-module", "m1x=" + m2.toString(), 172 "--module-source-path", src.toString(), 173 "-XDrawDiagnostics") 174 .outdir(classes) 175 .files(findJavaFiles(src.resolve("m1x").resolve("m1"), 176 src.resolve("m2x").resolve("m2"))) 177 .run(Expect.FAIL) 178 .writeAll() 179 .getOutputLines(Task.OutputKind.DIRECT); 180 181 List<String> expectedOut = Arrays.asList( 182 "Test.java:1:1: compiler.err.file.patched.and.msp: m1x, m2x", 183 "1 error" 184 ); 185 186 if (!expectedOut.equals(log)) 187 throw new Exception("expected output not found: " + log); 188 } 189 190 @Test 191 public void testSourcePath(Path base) throws Exception { 192 //note: avoiding use of java.base, as that gets special handling on some places: 193 Path src = base.resolve("src"); 194 tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, Other { }"); 195 Path srcPath = base.resolve("src-path"); 196 tb.writeJavaFiles(srcPath, "package javax.lang.model.element; interface Other { }"); 197 Path classes = base.resolve("classes"); 198 tb.createDirectories(classes); 199 200 List<String> log = new JavacTask(tb) 201 .options("--patch-module", "java.compiler=" + src.toString(), 202 "-sourcepath", srcPath.toString(), 203 "-XDrawDiagnostics") 204 .outdir(classes) 205 .files(src.resolve("javax/lang/model/element/Extra.java")) 206 .run(Expect.FAIL) 207 .writeAll() 208 .getOutputLines(Task.OutputKind.DIRECT); 209 210 List<String> expectedOut = Arrays.asList( 211 "Extra.java:1:75: compiler.err.cant.resolve: kindname.class, Other, , ", 212 "1 error" 213 ); 214 215 if (!expectedOut.equals(log)) 216 throw new Exception("expected output not found: " + log); 217 } 218 219 @Test 220 public void testClassPath(Path base) throws Exception { 221 Path cpSrc = base.resolve("cpSrc"); 222 tb.writeJavaFiles(cpSrc, "package p; public interface Other { }"); 223 Path cpClasses = base.resolve("cpClasses"); 224 tb.createDirectories(cpClasses); 225 226 String cpLog = new JavacTask(tb) 227 .outdir(cpClasses) 228 .files(findJavaFiles(cpSrc)) 229 .run() 230 .writeAll() 231 .getOutput(Task.OutputKind.DIRECT); 232 233 if (!cpLog.isEmpty()) 234 throw new Exception("expected output not found: " + cpLog); 235 236 Path src = base.resolve("src"); 237 //note: avoiding use of java.base, as that gets special handling on some places: 238 tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, p.Other { }"); 239 Path classes = base.resolve("classes"); 240 tb.createDirectories(classes); 241 242 List<String> log = new JavacTask(tb) 243 .options("--patch-module", "java.compiler=" + src.toString(), 244 "--class-path", cpClasses.toString(), 245 "-XDrawDiagnostics") 246 .outdir(classes) 247 .files(src.resolve("javax/lang/model/element/Extra.java")) 248 .run(Expect.FAIL) 249 .writeAll() 250 .getOutputLines(Task.OutputKind.DIRECT); 251 252 List<String> expectedOut = Arrays.asList( 253 "Extra.java:1:76: compiler.err.doesnt.exist: p", 254 "1 error" 255 ); 256 257 if (!expectedOut.equals(log)) 258 throw new Exception("expected output not found: " + log); 259 } 260 261 @Test 262 public void testNoModuleInfoOnSourcePath(Path base) throws Exception { 263 //note: avoiding use of java.base, as that gets special handling on some places: 264 Path src = base.resolve("src"); 265 tb.writeJavaFiles(src, 266 "module java.compiler {}", 267 "package javax.lang.model.element; public interface Extra { }"); 268 Path classes = base.resolve("classes"); 269 tb.createDirectories(classes); 270 271 List<String> log; 272 List<String> expected; 273 274 log = new JavacTask(tb) 275 .options("-XDrawDiagnostics", 276 "--patch-module", "java.compiler=" + src.toString()) 277 .outdir(classes) 278 .files(findJavaFiles(src)) 279 .run(Task.Expect.FAIL) 280 .writeAll() 281 .getOutputLines(Task.OutputKind.DIRECT); 282 283 expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.patched.module.sourcepath", 284 "1 error"); 285 286 if (!expected.equals(log)) 287 throw new Exception("expected output not found: " + log); 288 289 //multi-module mode: 290 log = new JavacTask(tb) 291 .options("-XDrawDiagnostics", 292 "--patch-module", "java.compiler=" + src.toString(), 293 "--module-source-path", "dummy") 294 .outdir(classes) 295 .files(findJavaFiles(src)) 296 .run(Task.Expect.FAIL) 297 .writeAll() 298 .getOutputLines(Task.OutputKind.DIRECT); 299 300 expected = Arrays.asList("- compiler.err.locn.module-info.not.allowed.on.patch.path: module-info.java", 301 "1 error"); 302 303 if (!expected.equals(log)) 304 throw new Exception("expected output not found: " + log); 305 } 306 307 @Test 308 public void testNoModuleInfoInClassOutput(Path base) throws Exception { 309 //note: avoiding use of java.base, as that gets special handling on some places: 310 Path srcMod = base.resolve("src-mod"); 311 tb.writeJavaFiles(srcMod, 312 "module mod {}"); 313 Path classes = base.resolve("classes").resolve("java.compiler"); 314 tb.createDirectories(classes); 315 316 String logMod = new JavacTask(tb) 317 .options() 318 .outdir(classes) 319 .files(findJavaFiles(srcMod)) 320 .run() 321 .writeAll() 322 .getOutput(Task.OutputKind.DIRECT); 323 324 if (!logMod.isEmpty()) 325 throw new Exception("unexpected output found: " + logMod); 326 327 Path src = base.resolve("src"); 328 tb.writeJavaFiles(src, 329 "package javax.lang.model.element; public interface Extra { }"); 330 tb.createDirectories(classes); 331 332 List<String> log; 333 List<String> expected; 334 335 log = new JavacTask(tb) 336 .options("-XDrawDiagnostics", 337 "--patch-module", "java.compiler=" + src.toString()) 338 .outdir(classes) 339 .files(findJavaFiles(src)) 340 .run(Task.Expect.FAIL) 341 .writeAll() 342 .getOutputLines(Task.OutputKind.DIRECT); 343 344 expected = Arrays.asList("Extra.java:1:1: compiler.err.module-info.with.patched.module.classoutput", 345 "1 error"); 346 347 if (!expected.equals(log)) 348 throw new Exception("expected output not found: " + log); 349 350 log = new JavacTask(tb) 351 .options("-XDrawDiagnostics", 352 "--patch-module", "java.compiler=" + src.toString(), 353 "--module-source-path", "dummy") 354 .outdir(classes.getParent()) 355 .files(findJavaFiles(src)) 356 .run(Task.Expect.FAIL) 357 .writeAll() 358 .getOutputLines(Task.OutputKind.DIRECT); 359 360 expected = Arrays.asList("- compiler.err.locn.module-info.not.allowed.on.patch.path: module-info.class", 361 "1 error"); 362 363 if (!expected.equals(log)) 364 throw new Exception("expected output not found: " + log); 365 } 366 367 @Test 368 public void testWithModulePath(Path base) throws Exception { 369 Path modSrc = base.resolve("modSrc"); 370 Path modules = base.resolve("modules"); 371 new ModuleBuilder(tb, "m1") 372 .classes("package pkg1; public interface E { }") 373 .build(modSrc, modules); 374 375 Path src = base.resolve("src"); 376 tb.writeJavaFiles(src, "package p; interface A extends pkg1.E { }"); 377 378 new JavacTask(tb, Task.Mode.CMDLINE) 379 .options("--module-path", modules.toString(), 380 "--patch-module", "m1=" + src.toString()) 381 .files(findJavaFiles(src)) 382 .run() 383 .writeAll(); 384 385 //checks module bounds still exist 386 new ModuleBuilder(tb, "m2") 387 .classes("package pkg2; public interface D { }") 388 .build(modSrc, modules); 389 390 Path src2 = base.resolve("src2"); 391 tb.writeJavaFiles(src2, "package p; interface A extends pkg2.D { }"); 392 393 List<String> log = new JavacTask(tb, Task.Mode.CMDLINE) 394 .options("-XDrawDiagnostics", 395 "--module-path", modules.toString(), 396 "--patch-module", "m1=" + src2.toString()) 397 .files(findJavaFiles(src2)) 398 .run(Task.Expect.FAIL) 399 .writeAll() 400 .getOutputLines(Task.OutputKind.DIRECT); 401 402 List<String> expected = Arrays.asList("A.java:1:32: compiler.err.package.not.visible: pkg2, (compiler.misc.not.def.access.does.not.read: m1, pkg2, m2)", 403 "1 error"); 404 405 if (!expected.equals(log)) 406 throw new Exception("expected output not found: " + log); 407 } 408 409 @Test 410 public void testWithUpgradeModulePath(Path base) throws Exception { 411 Path modSrc = base.resolve("modSrc"); 412 Path modules = base.resolve("modules"); 413 new ModuleBuilder(tb, "m1") 414 .classes("package pkg1; public interface E { }") 415 .build(modSrc, modules); 416 417 Path upgrSrc = base.resolve("upgradeSrc"); 418 Path upgrade = base.resolve("upgrade"); 419 new ModuleBuilder(tb, "m1") 420 .classes("package pkg1; public interface D { }") 421 .build(upgrSrc, upgrade); 422 423 Path src = base.resolve("src"); 424 tb.writeJavaFiles(src, "package p; interface A extends pkg1.D { }"); 425 426 new JavacTask(tb, Task.Mode.CMDLINE) 427 .options("--module-path", modules.toString(), 428 "--upgrade-module-path", upgrade.toString(), 429 "--patch-module", "m1=" + src.toString()) 430 .files(findJavaFiles(src)) 431 .run() 432 .writeAll(); 433 } 434 435 @Test 436 public void testUnnamedIsolation(Path base) throws Exception { 437 //note: avoiding use of java.base, as that gets special handling on some places: 438 Path sourcePath = base.resolve("source-path"); 439 tb.writeJavaFiles(sourcePath, "package src; public class Src {}"); 440 441 Path classPathSrc = base.resolve("class-path-src"); 442 tb.writeJavaFiles(classPathSrc, "package cp; public class CP { }"); 443 Path classPath = base.resolve("classPath"); 444 tb.createDirectories(classPath); 445 446 String cpLog = new JavacTask(tb) 447 .outdir(classPath) 448 .files(findJavaFiles(classPathSrc)) 449 .run() 450 .writeAll() 451 .getOutput(Task.OutputKind.DIRECT); 452 453 if (!cpLog.isEmpty()) 454 throw new Exception("expected output not found: " + cpLog); 455 456 Path modulePathSrc = base.resolve("module-path-src"); 457 tb.writeJavaFiles(modulePathSrc, 458 "module m {}", 459 "package m; public class M {}"); 460 Path modulePath = base.resolve("modulePath"); 461 tb.createDirectories(modulePath.resolve("m")); 462 463 String modLog = new JavacTask(tb) 464 .outdir(modulePath.resolve("m")) 465 .files(findJavaFiles(modulePathSrc)) 466 .run() 467 .writeAll() 468 .getOutput(Task.OutputKind.DIRECT); 469 470 if (!modLog.isEmpty()) 471 throw new Exception("expected output not found: " + modLog); 472 473 Path src = base.resolve("src"); 474 tb.writeJavaFiles(src, "package m; public class Extra { }"); 475 Path classes = base.resolve("classes"); 476 tb.createDirectories(classes); 477 478 String log = new JavacTask(tb) 479 .options("--patch-module", "m=" + sourcePath.toString(), 480 "--class-path", classPath.toString(), 481 "--source-path", sourcePath.toString(), 482 "--module-path", modulePath.toString(), 483 "--processor-path", System.getProperty("test.classes"), 484 "-XDaccessInternalAPI=true", 485 "-processor", CheckModuleContentProcessing.class.getName()) 486 .outdir(classes) 487 .files(findJavaFiles(sourcePath)) 488 .run() 489 .writeAll() 490 .getOutput(Task.OutputKind.DIRECT); 491 492 if (!log.isEmpty()) 493 throw new Exception("expected output not found: " + log); 494 } 495 496 @SupportedAnnotationTypes("*") 497 public static final class CheckModuleContentProcessing extends AbstractProcessor { 498 499 @Override 500 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 501 Symtab syms = Symtab.instance(((JavacProcessingEnvironment) processingEnv).getContext()); 502 Elements elements = processingEnv.getElementUtils(); 503 ModuleElement unnamedModule = syms.unnamedModule; 504 ModuleElement mModule = elements.getModuleElement("m"); 505 506 assertNonNull("mModule found", mModule); 507 assertNonNull("src.Src from m", elements.getTypeElement(mModule, "src.Src")); 508 assertNull("cp.CP not from m", elements.getTypeElement(mModule, "cp.CP")); 509 assertNull("src.Src not from unnamed", elements.getTypeElement(unnamedModule, "src.Src")); 510 assertNonNull("cp.CP from unnamed", elements.getTypeElement(unnamedModule, "cp.CP")); 511 512 return false; 513 } 514 515 @Override 516 public SourceVersion getSupportedSourceVersion() { 517 return SourceVersion.latest(); 518 } 519 520 private static void assertNonNull(String msg, Object val) { 521 if (val == null) { 522 throw new AssertionError(msg); 523 } 524 } 525 526 private static void assertNull(String msg, Object val) { 527 if (val != null) { 528 throw new AssertionError(msg); 529 } 530 } 531 } 532 533 @Test 534 public void testSingleModeIncremental(Path base) throws Exception { 535 //note: avoiding use of java.base, as that gets special handling on some places: 536 Path src = base.resolve("src"); 537 tb.writeJavaFiles(src, 538 "package javax.lang.model.element; public interface Extra extends Element { }", 539 "package javax.lang.model.element; public interface Extra2 extends Extra { }"); 540 Path classes = base.resolve("classes"); 541 tb.createDirectories(classes); 542 543 Thread.sleep(2000); //ensure newer timestamps on classfiles: 544 545 new JavacTask(tb) 546 .options("--patch-module", "java.compiler=" + src.toString()) 547 .outdir(classes) 548 .files(findJavaFiles(src)) 549 .run() 550 .writeAll() 551 .getOutput(Task.OutputKind.DIRECT); 552 553 List<String> log = new JavacTask(tb) 554 .options("--patch-module", "java.compiler=" + src.toString(), 555 "-verbose") 556 .outdir(classes) 557 .files(findJavaFiles(src.resolve("javax/lang/model/element/Extra2.java" 558 .replace("/", src.getFileSystem().getSeparator())))) 559 .run() 560 .writeAll() 561 .getOutputLines(Task.OutputKind.DIRECT) 562 .stream() 563 .filter(l -> l.contains("parsing")) 564 .collect(Collectors.toList()); 565 566 boolean parsesExtra2 = log.stream() 567 .anyMatch(l -> l.contains("Extra2.java")); 568 boolean parsesExtra = log.stream() 569 .anyMatch(l -> l.contains("Extra.java")); 570 571 if (!parsesExtra2 || parsesExtra) { 572 throw new AssertionError("Unexpected output: " + log); 573 } 574 } 575 576 @Test 577 public void testComplexMSPAndPatch(Path base) throws Exception { 578 //note: avoiding use of java.base, as that gets special handling on some places: 579 Path src1 = base.resolve("src1"); 580 Path src1ma = src1.resolve("ma"); 581 tb.writeJavaFiles(src1ma, 582 "module ma { exports ma; }", 583 "package ma; public class C1 { public static void method() { } }", 584 "package ma.impl; public class C2 { }"); 585 Path src1mb = src1.resolve("mb"); 586 tb.writeJavaFiles(src1mb, 587 "module mb { requires ma; }", 588 "package mb.impl; public class C2 { public static void method() { } }"); 589 Path src1mc = src1.resolve("mc"); 590 tb.writeJavaFiles(src1mc, 591 "module mc { }"); 592 Path classes1 = base.resolve("classes1"); 593 tb.createDirectories(classes1); 594 tb.cleanDirectory(classes1); 595 596 new JavacTask(tb) 597 .options("--module-source-path", src1.toString()) 598 .files(findJavaFiles(src1)) 599 .outdir(classes1) 600 .run() 601 .writeAll(); 602 603 //patching: 604 Path src2 = base.resolve("src2"); 605 Path src2ma = src2.resolve("ma"); 606 tb.writeJavaFiles(src2ma, 607 "package ma.impl; public class C2 { public static void extra() { ma.C1.method(); } }", 608 "package ma.impl; public class C3 { public void test() { C2.extra(); } }"); 609 Path src2mb = src2.resolve("mb"); 610 tb.writeJavaFiles(src2mb, 611 "package mb.impl; public class C3 { public void test() { C2.method(); ma.C1.method(); ma.impl.C2.extra(); } }"); 612 Path src2mc = src2.resolve("mc"); 613 tb.writeJavaFiles(src2mc, 614 "package mc.impl; public class C2 { public static void test() { } }", 615 //will require --add-reads ma: 616 "package mc.impl; public class C3 { public static void test() { ma.impl.C2.extra(); } }"); 617 Path src2mt = src2.resolve("mt"); 618 tb.writeJavaFiles(src2mt, 619 "module mt { requires ma; requires mb; }", 620 "package mt.impl; public class C2 { public static void test() { mb.impl.C2.method(); ma.impl.C2.extra(); } }", 621 "package mt.impl; public class C3 { public static void test() { C2.test(); mc.impl.C2.test(); } }"); 622 Path classes2 = base.resolve("classes2"); 623 tb.createDirectories(classes2); 624 tb.cleanDirectory(classes2); 625 626 Thread.sleep(2000); //ensure newer timestamps on classfiles: 627 628 new JavacTask(tb) 629 .options("--module-path", classes1.toString(), 630 "--patch-module", "ma=" + src2ma.toString(), 631 "--patch-module", "mb=" + src2mb.toString(), 632 "--add-exports", "ma/ma.impl=mb", 633 "--patch-module", "mc=" + src2mc.toString(), 634 "--add-reads", "mc=ma", 635 "--add-exports", "ma/ma.impl=mc", 636 "--add-exports", "ma/ma.impl=mt", 637 "--add-exports", "mb/mb.impl=mt", 638 "--add-exports", "mc/mc.impl=mt", 639 "--add-reads", "mt=mc", 640 "--module-source-path", src2.toString()) 641 .outdir(classes2) 642 .files(findJavaFiles(src2)) 643 .run() 644 .writeAll(); 645 646 //incremental compilation (C2 mustn't be compiled, C3 must): 647 tb.writeJavaFiles(src2ma, 648 "package ma.impl; public class C3 { public void test() { ma.C1.method(); C2.extra(); } }"); 649 tb.writeJavaFiles(src2mt, 650 "package mt.impl; public class C3 { public static void test() { mc.impl.C2.test(); C2.test(); } }"); 651 652 List<String> log = new JavacTask(tb) 653 .options("--module-path", classes1.toString(), 654 "--patch-module", "ma=" + src2ma.toString(), 655 "--patch-module", "mb=" + src2mb.toString(), 656 "--add-exports", "ma/ma.impl=mb", 657 "--patch-module", "mc=" + src2mc.toString(), 658 "--add-reads", "mc=ma", 659 "--add-exports", "ma/ma.impl=mc", 660 "--add-exports", "ma/ma.impl=mt", 661 "--add-exports", "mb/mb.impl=mt", 662 "--add-exports", "mc/mc.impl=mt", 663 "--add-reads", "mt=mc", 664 "--module-source-path", src2.toString(), 665 "--add-modules", "mc", 666 "-verbose") 667 .outdir(classes2) 668 .files(src2ma.resolve("ma").resolve("impl").resolve("C3.java"), 669 src2mt.resolve("mt").resolve("impl").resolve("C3.java")) 670 .run() 671 .writeAll() 672 .getOutputLines(Task.OutputKind.DIRECT) 673 .stream() 674 .filter(l -> l.contains("parsing")) 675 .collect(Collectors.toList()); 676 677 boolean parsesC3 = log.stream() 678 .anyMatch(l -> l.contains("C3.java")); 679 boolean parsesC2 = log.stream() 680 .anyMatch(l -> l.contains("C2.java")); 681 682 if (!parsesC3 || parsesC2) { 683 throw new AssertionError("Unexpected output: " + log); 684 } 685 } 686 687 private void checkFileExists(Path dir, String path) { 688 Path toCheck = dir.resolve(path.replace("/", dir.getFileSystem().getSeparator())); 689 690 if (!Files.exists(toCheck)) { 691 throw new AssertionError(toCheck.toString() + " does not exist!"); 692 } 693 } 694 }