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