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 * @summary Test the --add-reads option 27 * @library /tools/lib 28 * @modules jdk.compiler/com.sun.tools.javac.api 29 * jdk.compiler/com.sun.tools.javac.main 30 * jdk.jdeps/com.sun.tools.javap 31 * java.desktop 32 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavapTask ModuleTestBase 33 * @run main AddReadsTest 34 */ 35 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.util.Set; 39 40 import javax.annotation.processing.AbstractProcessor; 41 import javax.annotation.processing.RoundEnvironment; 42 import javax.annotation.processing.SupportedAnnotationTypes; 43 import javax.lang.model.SourceVersion; 44 import javax.lang.model.element.ModuleElement; 45 import javax.lang.model.element.ModuleElement.RequiresDirective; 46 import javax.lang.model.element.TypeElement; 47 import javax.lang.model.util.ElementFilter; 48 49 import toolbox.JarTask; 50 import toolbox.JavacTask; 51 import toolbox.JavapTask; 52 import toolbox.Task; 53 54 public class AddReadsTest extends ModuleTestBase { 55 56 public static void main(String... args) throws Exception { 57 new AddReadsTest().runTests(); 58 } 59 60 @Test 61 public void testAddReads(Path base) throws Exception { 62 Path src = base.resolve("src"); 63 Path src_m1 = src.resolve("m1"); 64 tb.writeJavaFiles(src_m1, 65 "module m1 { exports api; }", 66 "package api; public class Api { }"); 67 Path src_m2 = src.resolve("m2"); 68 tb.writeJavaFiles(src_m2, 69 "module m2 { }", 70 "package test; public class Test extends api.Api { }"); 71 Path classes = base.resolve("classes"); 72 tb.createDirectories(classes); 73 74 String log = new JavacTask(tb) 75 .options("-XDrawDiagnostics", 76 "--module-source-path", src.toString()) 77 .outdir(classes) 78 .files(findJavaFiles(src)) 79 .run(Task.Expect.FAIL) 80 .writeAll() 81 .getOutput(Task.OutputKind.DIRECT); 82 83 checkOutputContains(log, 84 "Test.java:1:44: compiler.err.not.def.access.package.cant.access: api.Api, api"); 85 86 //test add dependencies: 87 new JavacTask(tb) 88 .options("--add-reads", "m2=m1", 89 "--module-source-path", src.toString(), 90 "-processor", VerifyRequires.class.getName()) 91 .outdir(classes) 92 .files(findJavaFiles(src)) 93 .run() 94 .writeAll(); 95 96 String decompiled = new JavapTask(tb) 97 .options("-verbose", classes.resolve("m2").resolve("module-info.class").toString()) 98 .run() 99 .getOutput(Task.OutputKind.DIRECT); 100 101 if (decompiled.contains("m1")) { 102 throw new Exception("Incorrectly refers to m1 module."); 103 } 104 105 //cyclic dependencies OK when created through addReads: 106 new JavacTask(tb) 107 .options("--add-reads", "m2=m1", 108 "--add-reads", "m1=m2", 109 "--module-source-path", src.toString()) 110 .outdir(classes) 111 .files(findJavaFiles(src)) 112 .run() 113 .writeAll(); 114 115 tb.writeJavaFiles(src_m2, 116 "module m2 { requires m1; }"); 117 118 new JavacTask(tb) 119 .options("--add-reads", "m1=m2", 120 "--module-source-path", src.toString()) 121 .outdir(classes) 122 .files(findJavaFiles(src)) 123 .run() 124 .writeAll(); 125 } 126 127 @SupportedAnnotationTypes("*") 128 public static final class VerifyRequires extends AbstractProcessor { 129 130 @Override 131 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 132 ModuleElement m2Module = processingEnv.getElementUtils().getModuleElement("m2"); 133 if (m2Module == null) { 134 throw new AssertionError("Cannot find the m2 module!"); 135 } 136 boolean foundM1 = false; 137 for (RequiresDirective rd : ElementFilter.requiresIn(m2Module.getDirectives())) { 138 foundM1 |= rd.getDependency().getSimpleName().contentEquals("m1"); 139 } 140 if (!foundM1) { 141 throw new AssertionError("Cannot find the dependency on m1 module!"); 142 } 143 return false; 144 } 145 146 @Override 147 public SourceVersion getSupportedSourceVersion() { 148 return SourceVersion.latest(); 149 } 150 151 } 152 153 @Test 154 public void testAddReadsUnnamedModule(Path base) throws Exception { 155 Path jar = prepareTestJar(base); 156 157 Path moduleSrc = base.resolve("module-src"); 158 Path m1 = moduleSrc.resolve("m1"); 159 160 Path classes = base.resolve("classes"); 161 162 Files.createDirectories(classes); 163 164 tb.writeJavaFiles(m1, 165 "module m1 { }", 166 "package impl; public class Impl { api.Api api; }"); 167 168 new JavacTask(tb) 169 .options("--class-path", jar.toString(), 170 "--add-reads", "m1=ALL-UNNAMED", 171 "-XDrawDiagnostics") 172 .outdir(classes) 173 .files(findJavaFiles(moduleSrc)) 174 .run() 175 .writeAll(); 176 } 177 178 @Test 179 public void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception { 180 Path jar = prepareTestJar(base); 181 182 Path moduleSrc = base.resolve("module-src"); 183 Path m1 = moduleSrc.resolve("m1"); 184 185 Path classes = base.resolve("classes"); 186 187 Files.createDirectories(classes); 188 189 tb.writeJavaFiles(m1, 190 "module m1 { }", 191 "package api; public class Api { public static void test() { } }", 192 "package impl; public class Impl { { api.Api.test(); } }"); 193 194 new JavacTask(tb) 195 .options("--class-path", jar.toString(), 196 "--module-source-path", moduleSrc.toString(), 197 "--add-reads", "m1=ALL-UNNAMED", 198 "-XDrawDiagnostics") 199 .outdir(classes) 200 .files(m1.resolve("impl").resolve("Impl.java")) 201 .run() 202 .writeAll(); 203 } 204 205 @Test 206 public void testAddReadsUnnamedToJavaBase(Path base) throws Exception { 207 Path jar = prepareTestJar(base); 208 Path src = base.resolve("src"); 209 Path classes = base.resolve("classes"); 210 211 Files.createDirectories(classes); 212 213 tb.writeJavaFiles(src, 214 "package impl; public class Impl { api.Api a; }"); 215 216 new JavacTask(tb) 217 .options("--class-path", jar.toString(), 218 "--add-reads", "java.base=ALL-UNNAMED", 219 "-Xmodule:java.base") 220 .outdir(classes) 221 .files(src.resolve("impl").resolve("Impl.java")) 222 .run() 223 .writeAll(); 224 } 225 226 @Test 227 public void testAddReadsToJavaBase(Path base) throws Exception { 228 Path src = base.resolve("src"); 229 Path classes = base.resolve("classes"); 230 231 Files.createDirectories(classes); 232 233 tb.writeJavaFiles(src, 234 "package impl; public class Impl { javax.swing.JButton b; }"); 235 236 new JavacTask(tb) 237 .options("--add-modules", "java.desktop", 238 "--add-reads", "java.base=java.desktop", 239 "-Xmodule:java.base") 240 .outdir(classes) 241 .files(findJavaFiles(src)) 242 .run() 243 .writeAll(); 244 } 245 246 private Path prepareTestJar(Path base) throws Exception { 247 Path legacySrc = base.resolve("legacy-src"); 248 tb.writeJavaFiles(legacySrc, 249 "package api; public abstract class Api {}"); 250 Path legacyClasses = base.resolve("legacy-classes"); 251 Files.createDirectories(legacyClasses); 252 253 String log = new JavacTask(tb) 254 .options() 255 .outdir(legacyClasses) 256 .files(findJavaFiles(legacySrc)) 257 .run() 258 .writeAll() 259 .getOutput(Task.OutputKind.DIRECT); 260 261 if (!log.isEmpty()) { 262 throw new Exception("unexpected output: " + log); 263 } 264 265 Path lib = base.resolve("lib"); 266 267 Files.createDirectories(lib); 268 269 Path jar = lib.resolve("test-api-1.0.jar"); 270 271 new JarTask(tb, jar) 272 .baseDir(legacyClasses) 273 .files("api/Api.class") 274 .run(); 275 276 return jar; 277 } 278 279 @Test 280 public void testX(Path base) throws Exception { 281 Path src = base.resolve("src"); 282 Path src_m1 = src.resolve("m1"); 283 tb.writeJavaFiles(src_m1, 284 "module m1 { provides java.lang.Runnable with impl.Impl; }", 285 "package impl; public class Impl implements Runnable { public void run() { } }"); 286 Path classes = base.resolve("classes"); 287 tb.createDirectories(classes); 288 289 new JavacTask(tb) 290 .options("--module-source-path", src.toString()) 291 .outdir(classes) 292 .files(findJavaFiles(src)) 293 .run() 294 .writeAll(); 295 296 Path unnamedSrc = base.resolve("unnamed-src"); 297 Path unnamedClasses = base.resolve("unnamed-classes"); 298 299 Files.createDirectories(unnamedClasses); 300 301 tb.writeJavaFiles(unnamedSrc, 302 "package impl; public class Impl { }"); 303 304 new JavacTask(tb) 305 .options("--add-reads", "m1=ALL-UNNAMED", 306 "-Xmodule:m1", 307 "--module-path", classes.toString()) 308 .outdir(unnamedClasses) 309 .files(findJavaFiles(unnamedSrc)) 310 .run() 311 .writeAll(); 312 } 313 314 @Test 315 public void testAddSelf(Path base) throws Exception { 316 Path src = base.resolve("src"); 317 Path src_m1 = src.resolve("m1"); 318 tb.writeJavaFiles(src_m1, 319 "module m1 { exports p1; }", 320 "package p1; public class C1 { }"); 321 Path classes = base.resolve("classes"); 322 tb.createDirectories(classes); 323 324 new JavacTask(tb) 325 .options("--module-source-path", src.toString(), 326 "--add-reads", "m1=m1") 327 .outdir(classes) 328 .files(findJavaFiles(src)) 329 .run() 330 .writeAll(); 331 } 332 333 @Test 334 public void testEmpty(Path base) throws Exception { 335 Path src = base.resolve("src"); 336 tb.writeJavaFiles(src, "class Dummy { }"); 337 Path classes = base.resolve("classes"); 338 tb.createDirectories(classes); 339 340 testEmpty(src, classes, "--add-reads", ""); 341 testEmpty(src, classes, "--add-reads="); 342 } 343 344 private void testEmpty(Path src, Path classes, String... options) throws Exception { 345 String log = new JavacTask(tb, Task.Mode.CMDLINE) 346 .options(options) 347 .outdir(classes) 348 .files(findJavaFiles(src)) 349 .run(Task.Expect.FAIL) 350 .writeAll() 351 .getOutput(Task.OutputKind.DIRECT); 352 353 checkOutputContains(log, 354 "javac: no value for --add-reads option"); 355 } 356 357 @Test 358 public void testEmptyItem(Path base) throws Exception { 359 Path src = base.resolve("src"); 360 Path src_m1 = src.resolve("m1"); 361 tb.writeJavaFiles(src_m1, 362 "module m1 { exports p1; }", 363 "package p1; public class C1 { }"); 364 Path src_m2 = src.resolve("m2"); 365 tb.writeJavaFiles(src_m2, 366 "module m2 { }", 367 "package p2; class C2 { }"); 368 Path src_m3 = src.resolve("m3"); 369 tb.writeJavaFiles(src_m3, 370 "module m3 { }", 371 "package p3; class C3 { p1.C1 c1; }"); 372 Path classes = base.resolve("classes"); 373 tb.createDirectories(classes); 374 375 testEmptyItem(src, classes, "m3=,m1"); 376 testEmptyItem(src, classes, "m3=m1,,m2"); 377 testEmptyItem(src, classes, "m3=m1,"); 378 } 379 380 private void testEmptyItem(Path src, Path classes, String option) throws Exception { 381 new JavacTask(tb) 382 .options("--module-source-path", src.toString(), 383 "--add-reads", option) 384 .outdir(classes) 385 .files(findJavaFiles(src)) 386 .run() 387 .writeAll(); 388 } 389 390 @Test 391 public void testEmptyList(Path base) throws Exception { 392 Path src = base.resolve("src"); 393 Path src_m1 = src.resolve("m1"); 394 tb.writeJavaFiles(src_m1, 395 "module m1 { exports p1; }", 396 "package p1; public class C1 { }"); 397 Path src_m2 = src.resolve("m2"); 398 tb.writeJavaFiles(src_m2, 399 "module m2 { }", 400 "package p2; class C2 { }"); 401 Path src_m3 = src.resolve("m3"); 402 tb.writeJavaFiles(src_m3, 403 "module m3 { }", 404 "package p3; class C3 { p1.C1 c1; }"); 405 Path classes = base.resolve("classes"); 406 tb.createDirectories(classes); 407 408 testEmptyList(src, classes, "m3="); 409 testEmptyList(src, classes, "m3=,"); 410 } 411 412 private void testEmptyList(Path src, Path classes, String option) throws Exception { 413 String log = new JavacTask(tb, Task.Mode.CMDLINE) 414 .options("--module-source-path", src.toString(), 415 "--add-reads", option) 416 .outdir(classes) 417 .files(findJavaFiles(src)) 418 .run(Task.Expect.FAIL) 419 .writeAll() 420 .getOutput(Task.OutputKind.DIRECT); 421 422 checkOutputContains(log, 423 "javac: bad value for --add-reads option: '" + option + "'"); 424 } 425 426 @Test 427 public void testMultipleAddReads_DifferentModules(Path base) throws Exception { 428 Path src = base.resolve("src"); 429 Path src_m1 = src.resolve("m1"); 430 tb.writeJavaFiles(src_m1, 431 "module m1 { exports p1; }", 432 "package p1; public class C1 { }"); 433 Path src_m2 = src.resolve("m2"); 434 tb.writeJavaFiles(src_m2, 435 "module m2 { }", 436 "package p2; class C2 { p1.C1 c1; }"); 437 Path src_m3 = src.resolve("m3"); 438 tb.writeJavaFiles(src_m3, 439 "module m3 { }", 440 "package p3; class C3 { p1.C1 c1; }"); 441 Path classes = base.resolve("classes"); 442 tb.createDirectories(classes); 443 444 new JavacTask(tb) 445 .options("--module-source-path", src.toString(), 446 "--add-reads", "m2=m1", 447 "--add-reads", "m3=m1") 448 .outdir(classes) 449 .files(findJavaFiles(src)) 450 .run() 451 .writeAll(); 452 } 453 454 @Test 455 public void testMultipleAddReads_SameModule(Path base) throws Exception { 456 Path src = base.resolve("src"); 457 Path src_m1 = src.resolve("m1"); 458 tb.writeJavaFiles(src_m1, 459 "module m1 { exports p1; }", 460 "package p1; public class C1 { }"); 461 Path src_m2 = src.resolve("m2"); 462 tb.writeJavaFiles(src_m2, 463 "module m2 { exports p2; }", 464 "package p2; public class C2 { }"); 465 Path src_m3 = src.resolve("m3"); 466 tb.writeJavaFiles(src_m3, 467 "module m3 { }", 468 "package p3; class C3 { p1.C1 c1; p2.C2 c2; }"); 469 Path classes = base.resolve("classes"); 470 tb.createDirectories(classes); 471 472 new JavacTask(tb) 473 .options("--module-source-path", src.toString(), 474 "--add-reads", "m3=m1", 475 "--add-reads", "m3=m2") 476 .outdir(classes) 477 .files(findJavaFiles(src)) 478 .run() 479 .writeAll(); 480 } 481 482 @Test 483 public void testDuplicateAddReads_SameOption(Path base) throws Exception { 484 Path src = base.resolve("src"); 485 Path src_m1 = src.resolve("m1"); 486 tb.writeJavaFiles(src_m1, 487 "module m1 { exports p1; }", 488 "package p1; public class C1 { }"); 489 Path src_m2 = src.resolve("m2"); 490 tb.writeJavaFiles(src_m2, 491 "module m2 { exports p2; }", 492 "package p2; class C2 { p1.C1 c1; }"); 493 Path classes = base.resolve("classes"); 494 tb.createDirectories(classes); 495 496 new JavacTask(tb) 497 .options("--module-source-path", src.toString(), 498 "--add-reads", "m2=m1,m1") 499 .outdir(classes) 500 .files(findJavaFiles(src)) 501 .run() 502 .writeAll(); 503 } 504 505 @Test 506 public void testDuplicateAddReads_MultipleOptions(Path base) throws Exception { 507 Path src = base.resolve("src"); 508 Path src_m1 = src.resolve("m1"); 509 tb.writeJavaFiles(src_m1, 510 "module m1 { exports p1; }", 511 "package p1; public class C1 { }"); 512 Path src_m2 = src.resolve("m2"); 513 tb.writeJavaFiles(src_m2, 514 "module m2 { }", 515 "package p2; class C2 { p1.C1 c1; }"); 516 Path classes = base.resolve("classes"); 517 tb.createDirectories(classes); 518 519 new JavacTask(tb) 520 .options("--module-source-path", src.toString(), 521 "--add-reads", "m2=m1", 522 "--add-reads", "m2=m1") 523 .outdir(classes) 524 .files(findJavaFiles(src)) 525 .run() 526 .writeAll(); 527 } 528 529 @Test 530 public void testRepeatedAddReads(Path base) throws Exception { 531 Path src = base.resolve("src"); 532 Path src_m1 = src.resolve("m1"); 533 tb.writeJavaFiles(src_m1, 534 "module m1 { exports p1; }", 535 "package p1; public class C1 { }"); 536 Path src_m2 = src.resolve("m2"); 537 tb.writeJavaFiles(src_m2, 538 "module m2 { exports p2; }", 539 "package p2; public class C2 { }"); 540 Path src_m3 = src.resolve("m3"); 541 tb.writeJavaFiles(src_m3, 542 "module m3 { }", 543 "package p3; class C3 { p1.C1 c1; p2.C2 c2; }"); 544 Path classes = base.resolve("classes"); 545 tb.createDirectories(classes); 546 547 new JavacTask(tb) 548 .options("--module-source-path", src.toString(), 549 "--add-reads", "m3=m1", 550 "--add-reads", "m3=m2") 551 .outdir(classes) 552 .files(findJavaFiles(src)) 553 .run() 554 .writeAll(); 555 } 556 557 @Test 558 public void testNoEquals(Path base) throws Exception { 559 Path src = base.resolve("src"); 560 tb.writeJavaFiles(src, "class Dummy { }"); 561 Path classes = base.resolve("classes"); 562 tb.createDirectories(classes); 563 564 String log = new JavacTask(tb, Task.Mode.CMDLINE) 565 .options("-XDrawDiagnostics", 566 "--add-reads", "m1:m2") 567 .outdir(classes) 568 .files(findJavaFiles(src)) 569 .run(Task.Expect.FAIL) 570 .writeAll() 571 .getOutput(Task.OutputKind.DIRECT); 572 573 checkOutputContains(log, 574 "javac: bad value for --add-reads option: 'm1:m2'"); 575 } 576 577 @Test 578 public void testBadSourceName(Path base) throws Exception { 579 Path src = base.resolve("src"); 580 tb.writeJavaFiles(src, "class Dummy { }"); 581 Path classes = base.resolve("classes"); 582 tb.createDirectories(classes); 583 584 String log = new JavacTask(tb) 585 .options("-XDrawDiagnostics", 586 "--add-reads", "bad*Source=m2") 587 .outdir(classes) 588 .files(findJavaFiles(src)) 589 .run() 590 .writeAll() 591 .getOutput(Task.OutputKind.DIRECT); 592 593 checkOutputContains(log, 594 "- compiler.warn.bad.name.for.option: --add-reads, bad*Source"); 595 } 596 597 @Test 598 public void testBadTargetName(Path base) throws Exception { 599 Path src = base.resolve("src"); 600 Path src_m1 = src.resolve("m1"); 601 tb.writeJavaFiles(src_m1, 602 "module m1 { }", 603 "package p1; class C1 { }"); 604 Path classes = base.resolve("classes"); 605 tb.createDirectories(classes); 606 607 String log = new JavacTask(tb) 608 .options("-XDrawDiagnostics", 609 "--add-reads", "m1=badTarget!") 610 .outdir(classes) 611 .files(findJavaFiles(src)) 612 .run() 613 .writeAll() 614 .getOutput(Task.OutputKind.DIRECT); 615 616 checkOutputContains(log, 617 "- compiler.warn.bad.name.for.option: --add-reads, badTarget!"); 618 } 619 620 @Test 621 public void testSourceNameNotFound(Path base) throws Exception { 622 Path src = base.resolve("src"); 623 Path src_m1 = src.resolve("m1"); 624 tb.writeJavaFiles(src_m1, 625 "module m1 { exports p1; }", 626 "package p1; public class C1 { }"); 627 Path classes = base.resolve("classes"); 628 tb.createDirectories(classes); 629 630 String log = new JavacTask(tb) 631 .options("-XDrawDiagnostics", 632 "--add-reads", "missingSource=m1") 633 .outdir(classes) 634 .files(findJavaFiles(src)) 635 .run() 636 .writeAll() 637 .getOutput(Task.OutputKind.DIRECT); 638 639 checkOutputContains(log, 640 "- compiler.warn.module.for.option.not.found: --add-reads, missingSource"); 641 } 642 643 @Test 644 public void testTargetNameNotFound(Path base) throws Exception { 645 Path src = base.resolve("src"); 646 Path src_m1 = src.resolve("m1"); 647 tb.writeJavaFiles(src_m1, 648 "module m1 { exports p1; }", 649 "package p1; public class C1 { }"); 650 Path classes = base.resolve("classes"); 651 tb.createDirectories(classes); 652 653 String log = new JavacTask(tb) 654 .options("-XDrawDiagnostics", 655 "--add-reads", "m1=missingTarget") 656 .outdir(classes) 657 .files(findJavaFiles(src)) 658 .run() 659 .writeAll() 660 .getOutput(Task.OutputKind.DIRECT); 661 662 checkOutputContains(log, 663 "- compiler.warn.module.for.option.not.found: --add-reads, missingTarget"); 664 } 665 }