AddLimitMods.java revision 3530:581330357a3b
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 -addmods and -limitmods; also test the "enabled" modules. 27 * @library /tools/lib 28 * @modules 29 * jdk.compiler/com.sun.tools.javac.api 30 * jdk.compiler/com.sun.tools.javac.code 31 * jdk.compiler/com.sun.tools.javac.main 32 * jdk.compiler/com.sun.tools.javac.model 33 * jdk.compiler/com.sun.tools.javac.processing 34 * jdk.compiler/com.sun.tools.javac.util 35 * jdk.jdeps/com.sun.tools.javap 36 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavaTask ModuleTestBase 37 * @run main AddLimitMods 38 */ 39 40import java.io.File; 41import java.nio.file.Files; 42import java.nio.file.Path; 43import java.util.AbstractMap.SimpleEntry; 44import java.util.ArrayList; 45import java.util.Arrays; 46import java.util.Collections; 47import java.util.HashSet; 48import java.util.LinkedHashMap; 49import java.util.List; 50import java.util.Map; 51import java.util.Map.Entry; 52import java.util.Objects; 53import java.util.Set; 54 55import javax.annotation.processing.AbstractProcessor; 56import javax.annotation.processing.RoundEnvironment; 57import javax.annotation.processing.SupportedAnnotationTypes; 58import javax.annotation.processing.SupportedOptions; 59import javax.lang.model.SourceVersion; 60import javax.lang.model.element.ModuleElement; 61import javax.lang.model.element.TypeElement; 62 63import com.sun.tools.javac.code.Symbol.ClassSymbol; 64import com.sun.tools.javac.code.Symtab; 65import com.sun.tools.javac.model.JavacElements; 66import com.sun.tools.javac.processing.JavacProcessingEnvironment; 67import com.sun.tools.javac.util.Context; 68 69import toolbox.JarTask; 70import toolbox.JavacTask; 71import toolbox.JavaTask; 72import toolbox.Task; 73 74public class AddLimitMods extends ModuleTestBase { 75 76 public static void main(String... args) throws Exception { 77 AddLimitMods t = new AddLimitMods(); 78 t.runTests(); 79 } 80 81 @Test 82 public void testManual(Path base) throws Exception { 83 Path moduleSrc = base.resolve("module-src"); 84 Path m1 = moduleSrc.resolve("m1"); 85 86 tb.writeJavaFiles(m1, 87 "module m1 { requires m2; requires m3; }"); 88 89 Path m2 = moduleSrc.resolve("m2"); 90 91 tb.writeJavaFiles(m2, 92 "module m2 { requires m3; exports m2; }", 93 "package m2; public class M2 {}"); 94 95 Path m3 = moduleSrc.resolve("m3"); 96 97 tb.writeJavaFiles(m3, 98 "module m3 { exports m3; }", 99 "package m3; public class M3 {}"); 100 101 Path modulePath = base.resolve("module-path"); 102 103 Files.createDirectories(modulePath); 104 105 new JavacTask(tb) 106 .options("-modulesourcepath", moduleSrc.toString()) 107 .outdir(modulePath) 108 .files(findJavaFiles(m3)) 109 .run() 110 .writeAll(); 111 112 new JavacTask(tb) 113 .options("-modulesourcepath", moduleSrc.toString()) 114 .outdir(modulePath) 115 .files(findJavaFiles(m2)) 116 .run() 117 .writeAll(); 118 119 //real test 120 new JavacTask(tb) 121 .options("-modulepath", modulePath.toString(), 122 "-Xshouldstop:ifNoError=FLOW", 123 "-limitmods", "java.base") 124 .outdir(modulePath) 125 .files(findJavaFiles(m1)) 126 .run(Task.Expect.FAIL) 127 .writeAll(); 128 129 new JavacTask(tb) 130 .options("-modulepath", modulePath.toString(), 131 "-Xshouldstop:ifNoError=FLOW", 132 "-limitmods", "java.base", 133 "-addmods", "m2") 134 .outdir(modulePath) 135 .files(findJavaFiles(m1)) 136 .run(Task.Expect.FAIL) 137 .writeAll(); 138 139 new JavacTask(tb) 140 .options("-modulepath", modulePath.toString(), 141 "-Xshouldstop:ifNoError=FLOW", 142 "-limitmods", "java.base", 143 "-addmods", "m2,m3") 144 .outdir(modulePath) 145 .files(findJavaFiles(m1)) 146 .run() 147 .writeAll(); 148 149 new JavacTask(tb) 150 .options("-modulepath", modulePath.toString(), 151 "-Xshouldstop:ifNoError=FLOW", 152 "-limitmods", "m2") 153 .outdir(modulePath) 154 .files(findJavaFiles(m1)) 155 .run() 156 .writeAll(); 157 158 new JavacTask(tb) 159 .options("-modulepath", modulePath.toString(), 160 "-Xshouldstop:ifNoError=FLOW", 161 "-limitmods", "m3") 162 .outdir(modulePath) 163 .files(findJavaFiles(m1)) 164 .run(Task.Expect.FAIL) 165 .writeAll(); 166 167 new JavacTask(tb) 168 .options("-modulepath", modulePath.toString(), 169 "-Xshouldstop:ifNoError=FLOW", 170 "-limitmods", "m3", 171 "-addmods", "m2") 172 .outdir(modulePath) 173 .files(findJavaFiles(m1)) 174 .run() 175 .writeAll(); 176 } 177 178 @Test 179 public void testObservableForUnnamed(Path base) throws Exception { 180 Path src = base.resolve("src"); 181 182 tb.writeJavaFiles(src, 183 "package test;\n" + 184 "@javax.annotation.Generated(\"test\")\n" + 185 "public class Test {\n" + 186 " com.sun.tools.javac.Main m;\n" + 187 " javax.xml.bind.JAXBException e;\n" + 188 "}\n"); 189 190 Path out = base.resolve("out"); 191 192 Files.createDirectories(out); 193 194 for (Entry<String[], String> variant : variants) { 195 System.err.println("running variant: options=" + Arrays.asList(variant.getKey()) + ", expected log: " + variant.getValue()); 196 197 List<String> options = new ArrayList<>(); 198 options.add("-XDrawDiagnostics"); 199 options.addAll(Arrays.asList(variant.getKey())); 200 201 String log = new JavacTask(tb) 202 .options(options.toArray(new String[0])) 203 .outdir(out) 204 .files(findJavaFiles(src)) 205 .run(variant.getValue() == null ? Task.Expect.SUCCESS : Task.Expect.FAIL) 206 .writeAll() 207 .getOutput(Task.OutputKind.DIRECT); 208 209 log = log.replace(System.getProperty("line.separator"), "\n"); 210 211 if (variant.getValue() != null && !log.equals(variant.getValue())) { 212 throw new AssertionError(); 213 } 214 } 215 } 216 217 private static final List<Entry<String[], String>> variants = Arrays.asList( 218 new SimpleEntry<String[], String>(new String[] {}, 219 "Test.java:2:18: compiler.err.doesnt.exist: javax.annotation\n" 220 + "Test.java:5:19: compiler.err.doesnt.exist: javax.xml.bind\n" 221 + "2 errors\n"), 222 new SimpleEntry<String[], String>(new String[] {"-addmods", "java.annotations.common,java.xml.bind"}, 223 null), 224 new SimpleEntry<String[], String>(new String[] {"-limitmods", "java.xml.ws,jdk.compiler"}, 225 null), 226 new SimpleEntry<String[], String>(new String[] {"-addmods", "ALL-SYSTEM"}, 227 null) 228 ); 229 230 @Test 231 public void testAllModulePath(Path base) throws Exception { 232 if (Files.isDirectory(base)) 233 tb.cleanDirectory(base); 234 235 Path moduleSrc = base.resolve("module-src"); 236 Path m1 = moduleSrc.resolve("m1"); 237 238 tb.writeJavaFiles(m1, 239 "module m1 { exports api; }", 240 "package api; public class Api { }"); 241 242 Path modulePath = base.resolve("module-path"); 243 244 Files.createDirectories(modulePath); 245 246 new JavacTask(tb) 247 .options("-modulesourcepath", moduleSrc.toString()) 248 .outdir(modulePath) 249 .files(findJavaFiles(moduleSrc)) 250 .run() 251 .writeAll(); 252 253 Path cpSrc = base.resolve("cp-src"); 254 tb.writeJavaFiles(cpSrc, "package test; public class Test { api.Api api; }"); 255 256 Path cpOut = base.resolve("cp-out"); 257 258 Files.createDirectories(cpOut); 259 260 new JavacTask(tb) 261 .options("-modulepath", modulePath.toString()) 262 .outdir(cpOut) 263 .files(findJavaFiles(cpSrc)) 264 .run(Task.Expect.FAIL) 265 .writeAll(); 266 267 new JavacTask(tb) 268 .options("-modulepath", modulePath.toString(), 269 "-addmods", "ALL-MODULE-PATH") 270 .outdir(cpOut) 271 .files(findJavaFiles(cpSrc)) 272 .run() 273 .writeAll(); 274 275 List<String> actual; 276 List<String> expected = Arrays.asList( 277 "- compiler.err.addmods.all.module.path.invalid", 278 "1 error"); 279 280 actual = new JavacTask(tb) 281 .options("-modulesourcepath", moduleSrc.toString(), 282 "-XDrawDiagnostics", 283 "-addmods", "ALL-MODULE-PATH") 284 .outdir(modulePath) 285 .files(findJavaFiles(moduleSrc)) 286 .run(Task.Expect.FAIL) 287 .writeAll() 288 .getOutputLines(Task.OutputKind.DIRECT); 289 290 if (!Objects.equals(actual, expected)) { 291 throw new IllegalStateException("incorrect errors; actual=" + actual + "; expected=" + expected); 292 } 293 294 actual = new JavacTask(tb) 295 .options("-Xmodule:java.base", 296 "-XDrawDiagnostics", 297 "-addmods", "ALL-MODULE-PATH") 298 .outdir(cpOut) 299 .files(findJavaFiles(cpSrc)) 300 .run(Task.Expect.FAIL) 301 .writeAll() 302 .getOutputLines(Task.OutputKind.DIRECT); 303 304 if (!Objects.equals(actual, expected)) { 305 throw new IllegalStateException("incorrect errors; actual=" + actual + "; expected=" + expected); 306 } 307 308 actual = new JavacTask(tb, Task.Mode.CMDLINE) 309 .options("-source", "8", "-target", "8", 310 "-XDrawDiagnostics", 311 "-addmods", "ALL-MODULE-PATH") 312 .outdir(cpOut) 313 .files(findJavaFiles(cpSrc)) 314 .run(Task.Expect.FAIL) 315 .writeAll() 316 .getOutputLines(Task.OutputKind.DIRECT); 317 318 if (!actual.contains("javac: option -addmods not allowed with target 1.8")) { 319 throw new IllegalStateException("incorrect errors; actual=" + actual); 320 } 321 322 tb.writeJavaFiles(cpSrc, "module m1 {}"); 323 324 actual = new JavacTask(tb) 325 .options("-XDrawDiagnostics", 326 "-addmods", "ALL-MODULE-PATH") 327 .outdir(cpOut) 328 .files(findJavaFiles(cpSrc)) 329 .run(Task.Expect.FAIL) 330 .writeAll() 331 .getOutputLines(Task.OutputKind.DIRECT); 332 333 if (!Objects.equals(actual, expected)) { 334 throw new IllegalStateException("incorrect errors; actual=" + actual + "; expected=" + expected); 335 } 336 } 337 338 @Test 339 public void testRuntime2Compile(Path base) throws Exception { 340 Path classpathSrc = base.resolve("classpath-src"); 341 Path classpathOut = base.resolve("classpath-out"); 342 343 tb.writeJavaFiles(classpathSrc, 344 generateCheckAccessibleClass("cp.CP")); 345 346 Files.createDirectories(classpathOut); 347 348 new JavacTask(tb) 349 .outdir(classpathOut) 350 .files(findJavaFiles(classpathSrc)) 351 .run() 352 .writeAll() 353 .getOutput(Task.OutputKind.DIRECT); 354 355 Path automaticSrc = base.resolve("automatic-src"); 356 Path automaticOut = base.resolve("automatic-out"); 357 358 tb.writeJavaFiles(automaticSrc, 359 generateCheckAccessibleClass("automatic.Automatic")); 360 361 Files.createDirectories(automaticOut); 362 363 new JavacTask(tb) 364 .outdir(automaticOut) 365 .files(findJavaFiles(automaticSrc)) 366 .run() 367 .writeAll() 368 .getOutput(Task.OutputKind.DIRECT); 369 370 Path modulePath = base.resolve("module-path"); 371 372 Files.createDirectories(modulePath); 373 374 Path automaticJar = modulePath.resolve("automatic.jar"); 375 376 new JarTask(tb, automaticJar) 377 .baseDir(automaticOut) 378 .files("automatic/Automatic.class") 379 .run(); 380 381 Path moduleSrc = base.resolve("module-src"); 382 Path m1 = moduleSrc.resolve("m1"); 383 384 tb.writeJavaFiles(m1, 385 "module m1 { exports api; }", 386 "package api; public class Api { public void test() { } }"); 387 388 new JavacTask(tb) 389 .options("-modulesourcepath", moduleSrc.toString()) 390 .outdir(modulePath) 391 .files(findJavaFiles(moduleSrc)) 392 .run() 393 .writeAll() 394 .getOutput(Task.OutputKind.DIRECT); 395 396 int index = 0; 397 398 for (String moduleInfo : MODULE_INFO_VARIANTS) { 399 for (String[] options : OPTIONS_VARIANTS) { 400 index++; 401 402 System.err.println("running check: " + moduleInfo + "; " + Arrays.asList(options)); 403 404 Path m2Runtime = base.resolve(index + "-runtime").resolve("m2"); 405 Path out = base.resolve(index + "-runtime").resolve("out").resolve("m2"); 406 407 Files.createDirectories(out); 408 409 StringBuilder testClassNamed = new StringBuilder(); 410 411 testClassNamed.append("package test;\n" + 412 "public class Test {\n" + 413 " public static void main(String... args) throws Exception {\n"); 414 415 for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) { 416 testClassNamed.append(" System.err.println(\"visible:" + e.getKey() + ":\" + java.lang.reflect.Layer.boot().findModule(\"" + e.getKey() + "\").isPresent());\n"); 417 } 418 419 testClassNamed.append(" Class<?> cp = Class.forName(Test.class.getClassLoader().getUnnamedModule(), \"cp.CP\");\n"); 420 testClassNamed.append(" cp.getDeclaredMethod(\"runMe\").invoke(null);\n"); 421 422 testClassNamed.append(" Class<?> automatic = Class.forName(java.lang.reflect.Layer.boot().findModule(\"automatic\").get(), \"automatic.Automatic\");\n"); 423 testClassNamed.append(" automatic.getDeclaredMethod(\"runMe\").invoke(null);\n"); 424 425 testClassNamed.append(" }\n" + 426 "}"); 427 428 tb.writeJavaFiles(m2Runtime, moduleInfo, testClassNamed.toString()); 429 430 new JavacTask(tb) 431 .options("-modulepath", modulePath.toString()) 432 .outdir(out) 433 .files(findJavaFiles(m2Runtime)) 434 .run() 435 .writeAll(); 436 437 boolean success; 438 String output; 439 440 try { 441 output = new JavaTask(tb) 442 .vmOptions(augmentOptions(options, 443 Collections.emptyList(), 444 "-modulepath", modulePath.toString() + File.pathSeparator + out.getParent().toString(), 445 "-classpath", classpathOut.toString(), 446 "-XaddReads:m2=ALL-UNNAMED,automatic", 447 "-m", "m2/test.Test")) 448 .run() 449 .writeAll() 450 .getOutput(Task.OutputKind.STDERR); 451 452 success = true; 453 } catch (Task.TaskError err) { 454 success = false; 455 output = ""; 456 } 457 458 Path m2 = base.resolve(String.valueOf(index)).resolve("m2"); 459 460 tb.writeJavaFiles(m2, 461 moduleInfo, 462 "package test;\n" + 463 "public class Test {}\n"); 464 465 List<String> auxOptions = success ? Arrays.asList( 466 "-processorpath", System.getProperty("test.class.path"), 467 "-processor", CheckVisibleModule.class.getName(), 468 "-Aoutput=" + output, 469 "-XDaccessInternalAPI=true" 470 ) : Collections.emptyList(); 471 new JavacTask(tb) 472 .options(augmentOptions(options, 473 auxOptions, 474 "-modulepath", modulePath.toString(), 475 "-classpath", classpathOut.toString(), 476 "-Xshouldstop:ifNoError=FLOW")) 477 .outdir(modulePath) 478 .files(findJavaFiles(m2)) 479 .run(success ? Task.Expect.SUCCESS : Task.Expect.FAIL) 480 .writeAll(); 481 } 482 } 483 } 484 485 private String generateCheckAccessibleClass(String fqn) { 486 String packageName = fqn.substring(0, fqn.lastIndexOf('.')); 487 String simpleName = fqn.substring(fqn.lastIndexOf('.') + 1); 488 StringBuilder checkClassesAccessible = new StringBuilder(); 489 checkClassesAccessible.append("package " + packageName + ";" + 490 "public class " + simpleName + " {" + 491 " public static void runMe() throws Exception {"); 492 for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) { 493 checkClassesAccessible.append("try {"); 494 checkClassesAccessible.append("Class.forName(\"" + e.getValue() + "\").newInstance();"); 495 checkClassesAccessible.append("System.err.println(\"" + fqn + ":" + e.getKey() + ":true\");"); 496 checkClassesAccessible.append("} catch (Exception ex) {"); 497 checkClassesAccessible.append("System.err.println(\"" + fqn + ":" + e.getKey() + ":false\");"); 498 checkClassesAccessible.append("}"); 499 } 500 501 checkClassesAccessible.append(" }\n" + 502 "}"); 503 504 return checkClassesAccessible.toString(); 505 } 506 507 private static final Map<String, String> MODULES_TO_CHECK_TO_SAMPLE_CLASS = new LinkedHashMap<>(); 508 509 static { 510 MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m1", "api.Api"); 511 MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m2", "test.Test"); 512 MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.base", "java.lang.Object"); 513 MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.compiler", "javax.tools.ToolProvider"); 514 MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("jdk.compiler", "com.sun.tools.javac.Main"); 515 }; 516 517 @SupportedAnnotationTypes("*") 518 @SupportedOptions("output") 519 public static final class CheckVisibleModule extends AbstractProcessor { 520 521 @Override 522 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 523 String expected = processingEnv.getOptions().get("output"); 524 Set<String> expectedElements = new HashSet<>(Arrays.asList(expected.split(System.getProperty("line.separator")))); 525 Context context = ((JavacProcessingEnvironment) processingEnv).getContext(); 526 Symtab syms = Symtab.instance(context); 527 528 for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) { 529 String module = e.getKey(); 530 ModuleElement mod = processingEnv.getElementUtils().getModuleElement(module); 531 String visible = "visible:" + module + ":" + (mod != null); 532 533 if (!expectedElements.contains(visible)) { 534 throw new AssertionError("actual: " + visible + "; expected: " + expected); 535 } 536 537 JavacElements javacElements = JavacElements.instance(context); 538 ClassSymbol unnamedClass = javacElements.getTypeElement(syms.unnamedModule, e.getValue()); 539 String unnamed = "cp.CP:" + module + ":" + (unnamedClass != null); 540 541 if (!expectedElements.contains(unnamed)) { 542 throw new AssertionError("actual: " + unnamed + "; expected: " + expected); 543 } 544 545 ModuleElement automaticMod = processingEnv.getElementUtils().getModuleElement("automatic"); 546 ClassSymbol automaticClass = javacElements.getTypeElement(automaticMod, e.getValue()); 547 String automatic = "automatic.Automatic:" + module + ":" + (automaticClass != null); 548 549 if (!expectedElements.contains(automatic)) { 550 throw new AssertionError("actual: " + automatic + "; expected: " + expected); 551 } 552 } 553 554 return false; 555 } 556 557 @Override 558 public SourceVersion getSupportedSourceVersion() { 559 return SourceVersion.latest(); 560 } 561 562 } 563 564 public String[] augmentOptions(String[] options, List<String> auxOptions, String... baseOptions) { 565 List<String> all = new ArrayList<>(); 566 567 all.addAll(Arrays.asList(options)); 568 all.addAll(Arrays.asList(baseOptions)); 569 all.addAll(auxOptions); 570 571 return all.toArray(new String[0]); 572 } 573 574 private static final String[] MODULE_INFO_VARIANTS = { 575 "module m2 { exports test; }", 576 "module m2 { requires m1; exports test; }", 577 "module m2 { requires jdk.compiler; exports test; }", 578 }; 579 580 private static final String[][] OPTIONS_VARIANTS = { 581 {"-addmods", "automatic"}, 582 {"-addmods", "m1,automatic"}, 583 {"-addmods", "jdk.compiler,automatic"}, 584 {"-addmods", "m1,jdk.compiler,automatic"}, 585 {"-addmods", "ALL-SYSTEM,automatic"}, 586 {"-limitmods", "java.base", "-addmods", "automatic"}, 587 {"-limitmods", "java.base", "-addmods", "ALL-SYSTEM,automatic"}, 588 {"-limitmods", "m2", "-addmods", "automatic"}, 589 {"-limitmods", "jdk.compiler", "-addmods", "automatic"}, 590 }; 591} 592