1 /* 2 * Copyright (c) 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 8208184 27 * @summary tests for module resolution 28 * @library /tools/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.main 32 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase 33 * @run main QueryBeforeEnter 34 */ 35 36 import java.io.File; 37 import java.io.IOException; 38 import java.io.OutputStream; 39 import java.net.URI; 40 import java.net.URISyntaxException; 41 import java.nio.file.*; 42 import java.util.ArrayList; 43 import java.util.HashMap; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Map.Entry; 47 import java.util.Arrays; 48 import java.util.Set; 49 50 import javax.annotation.processing.AbstractProcessor; 51 import javax.annotation.processing.RoundEnvironment; 52 import javax.annotation.processing.SupportedAnnotationTypes; 53 import javax.lang.model.SourceVersion; 54 import javax.lang.model.element.TypeElement; 55 import javax.tools.FileObject; 56 import javax.tools.ForwardingJavaFileManager; 57 import javax.tools.JavaCompiler; 58 import javax.tools.JavaFileManager; 59 import javax.tools.JavaFileObject; 60 import javax.tools.JavaFileObject.Kind; 61 import javax.tools.SimpleJavaFileObject; 62 import javax.tools.StandardJavaFileManager; 63 import javax.tools.StandardLocation; 64 import javax.tools.ToolProvider; 65 66 // import com.sun.source.util.JavacTask; 67 import com.sun.source.util.Plugin; 68 import com.sun.source.util.TaskEvent; 69 import com.sun.source.util.TaskListener; 70 import com.sun.tools.javac.Main; 71 72 import toolbox.JavacTask; 73 import toolbox.Task; 74 import toolbox.ToolBox; 75 76 public class QueryBeforeEnter extends ModuleTestBase { main(String... args)77 public static void main(String... args) throws Exception { 78 QueryBeforeEnter t = new QueryBeforeEnter(); 79 t.runTests(); 80 } 81 82 @Test testEmpty(Path base)83 public void testEmpty(Path base) throws Exception { 84 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 85 com.sun.source.util.JavacTask task = 86 (com.sun.source.util.JavacTask) javaCompiler.getTask(null, null, null, null, null, null); 87 TypeElement jlString = task.getElements().getTypeElement("java.lang.String"); 88 89 assertNotNull(jlString); 90 } 91 92 @Test testUnnamed(Path base)93 public void testUnnamed(Path base) throws Exception { 94 Path moduleSrc = base.resolve("module-src"); 95 Path m1 = moduleSrc.resolve("m1x"); 96 97 tb.writeJavaFiles(m1, 98 "module m1x { exports m1x; }", 99 "package m1x; public class M1 {}"); 100 101 Path m2 = moduleSrc.resolve("m2x"); 102 103 tb.writeJavaFiles(m2, 104 "module m2x { exports m2x; }", 105 "package m2x; public class M2 {}"); 106 107 Path modulePath = base.resolve("module-path"); 108 109 Files.createDirectories(modulePath); 110 111 new JavacTask(tb) 112 .options("--module-source-path", moduleSrc.toString()) 113 .outdir(modulePath) 114 .files(findJavaFiles(moduleSrc)) 115 .run() 116 .writeAll(); 117 118 Path cpSrc = base.resolve("cp-src"); 119 120 tb.writeJavaFiles(cpSrc, 121 "package cp; public class CP {}"); 122 123 Path cp = base.resolve("cp"); 124 125 Files.createDirectories(cp); 126 127 new JavacTask(tb) 128 .outdir(cp) 129 .files(findJavaFiles(cpSrc)) 130 .run() 131 .writeAll(); 132 133 Path src = base.resolve("src"); 134 135 tb.writeJavaFiles(src, 136 "package test; public class Test1 {}", 137 "package test; public class Test2 {}"); 138 139 Path out = base.resolve("out"); 140 141 Files.createDirectories(out); 142 143 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 144 try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) { 145 com.sun.source.util.JavacTask task = 146 (com.sun.source.util.JavacTask) javaCompiler.getTask(null, 147 null, 148 d -> { throw new IllegalStateException(d.toString()); }, 149 Arrays.asList("--module-path", modulePath.toString(), 150 "--class-path", cp.toString(), 151 "-sourcepath", src.toString()), 152 null, 153 fm.getJavaFileObjects(src.resolve("test").resolve("Test2.java"))); 154 assertNotNull(task.getElements().getTypeElement("java.lang.String")); 155 assertNotNull(task.getElements().getTypeElement("javax.tools.ToolProvider")); 156 assertNull(task.getElements().getTypeElement("m1x.M1")); 157 assertNull(task.getElements().getTypeElement("m2x.M2")); 158 assertNotNull(task.getElements().getTypeElement("cp.CP")); 159 assertNotNull(task.getElements().getTypeElement("test.Test1")); 160 assertNotNull(task.getElements().getTypeElement("test.Test2")); 161 assertNotNull(task.getElements().getModuleElement("java.base")); 162 assertNotNull(task.getElements().getModuleElement("java.compiler")); 163 assertNull(task.getElements().getModuleElement("m1x")); 164 assertNull(task.getElements().getModuleElement("m2x")); 165 } 166 } 167 168 @Test testSingleNamed(Path base)169 public void testSingleNamed(Path base) throws Exception { 170 Path moduleSrc = base.resolve("module-src"); 171 Path m1 = moduleSrc.resolve("m1x"); 172 173 tb.writeJavaFiles(m1, 174 "module m1x { exports m1x; }", 175 "package m1x; public class M1 {}"); 176 177 Path m2 = moduleSrc.resolve("m2x"); 178 179 tb.writeJavaFiles(m2, 180 "module m2x { exports m2x; }", 181 "package m2x; public class M2 {}"); 182 183 Path modulePath = base.resolve("module-path"); 184 185 Files.createDirectories(modulePath); 186 187 new JavacTask(tb) 188 .options("--module-source-path", moduleSrc.toString()) 189 .outdir(modulePath) 190 .files(findJavaFiles(moduleSrc)) 191 .run() 192 .writeAll(); 193 194 Path cpSrc = base.resolve("cp-src"); 195 196 tb.writeJavaFiles(cpSrc, 197 "package cp; public class CP {}"); 198 199 Path cp = base.resolve("cp"); 200 201 Files.createDirectories(cp); 202 203 new JavacTask(tb) 204 .outdir(cp) 205 .files(findJavaFiles(cpSrc)) 206 .run() 207 .writeAll(); 208 209 Path src = base.resolve("src"); 210 211 tb.writeJavaFiles(src, 212 "module test { requires java.base; requires m1x; } ", 213 "package test; public class Test {}"); 214 215 Path out = base.resolve("out"); 216 217 Files.createDirectories(out); 218 219 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 220 try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) { 221 com.sun.source.util.JavacTask task = 222 (com.sun.source.util.JavacTask) javaCompiler.getTask(null, 223 null, 224 d -> { throw new IllegalStateException(d.toString()); }, 225 Arrays.asList("--module-path", modulePath.toString(), 226 "--class-path", cp.toString(), 227 "-sourcepath", src.toString()), 228 null, 229 fm.getJavaFileObjects(findJavaFiles(src))); 230 assertNotNull(task.getElements().getTypeElement("java.lang.String")); 231 assertNull(task.getElements().getTypeElement("javax.tools.ToolProvider")); 232 assertNotNull(task.getElements().getTypeElement("m1x.M1")); 233 assertNull(task.getElements().getTypeElement("m2x.M2")); 234 assertNotNull(task.getElements().getTypeElement("test.Test")); 235 assertNotNull(task.getElements().getModuleElement("java.base")); 236 assertNull(task.getElements().getModuleElement("java.compiler")); 237 assertNotNull(task.getElements().getModuleElement("m1x")); 238 assertNull(task.getElements().getModuleElement("m2x")); 239 assertNotNull(task.getElements().getModuleElement("test")); 240 } 241 } 242 243 @Test testMultiModule(Path base)244 public void testMultiModule(Path base) throws Exception { 245 Path modulePathSrc = base.resolve("module-path-src"); 246 Path m1 = modulePathSrc.resolve("m1x"); 247 248 tb.writeJavaFiles(m1, 249 "module m1x { exports m1x; }", 250 "package m1x; public class M1 {}"); 251 252 Path m2 = modulePathSrc.resolve("m2x"); 253 254 tb.writeJavaFiles(m2, 255 "module m2x { exports m2x; }", 256 "package m2x; public class M2 {}"); 257 258 Path modulePath = base.resolve("module-path"); 259 260 Files.createDirectories(modulePath); 261 262 new JavacTask(tb) 263 .options("--module-source-path", modulePathSrc.toString()) 264 .outdir(modulePath) 265 .files(findJavaFiles(modulePathSrc)) 266 .run() 267 .writeAll(); 268 269 Path cpSrc = base.resolve("cp-src"); 270 271 tb.writeJavaFiles(cpSrc, 272 "package cp; public class CP {}"); 273 274 Path cp = base.resolve("cp"); 275 276 Files.createDirectories(cp); 277 278 new JavacTask(tb) 279 .outdir(cp) 280 .files(findJavaFiles(cpSrc)) 281 .run() 282 .writeAll(); 283 284 Path moduleSrc = base.resolve("module-src"); 285 Path m3 = moduleSrc.resolve("m3x"); 286 287 tb.writeJavaFiles(m3, 288 "module m3x { requires m1x; exports m3x; }", 289 "package m3x; public class M3 { }"); 290 291 Path m4 = moduleSrc.resolve("m4x"); 292 293 tb.writeJavaFiles(m4, 294 "module m4x { exports m4x; }", 295 "package m4x; public class M4 {}"); 296 297 Path out = base.resolve("out"); 298 299 Files.createDirectories(out); 300 301 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 302 try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) { 303 com.sun.source.util.JavacTask task = 304 (com.sun.source.util.JavacTask) javaCompiler.getTask(null, 305 null, 306 d -> { throw new IllegalStateException(d.toString()); }, 307 Arrays.asList("--module-path", modulePath.toString(), 308 "--class-path", cp.toString(), 309 "--module-source-path", moduleSrc.toString(), 310 "-d", out.toString()), 311 null, 312 fm.getJavaFileObjects(findJavaFiles(moduleSrc))); 313 assertNotNull(task.getElements().getTypeElement("java.lang.String")); 314 assertNull(task.getElements().getTypeElement("javax.tools.ToolProvider")); 315 assertNotNull(task.getElements().getTypeElement("m1x.M1")); 316 assertNull(task.getElements().getTypeElement("m2x.M2")); 317 assertNotNull(task.getElements().getTypeElement("m3x.M3")); 318 assertNotNull(task.getElements().getTypeElement("m4x.M4")); 319 assertNotNull(task.getElements().getModuleElement("java.base")); 320 assertNull(task.getElements().getModuleElement("java.compiler")); 321 assertNotNull(task.getElements().getModuleElement("m1x")); 322 assertNull(task.getElements().getModuleElement("m2x")); 323 assertNotNull(task.getElements().getModuleElement("m3x")); 324 assertNotNull(task.getElements().getModuleElement("m4x")); 325 } 326 } 327 328 @Test testTooSoon(Path base)329 public void testTooSoon(Path base) throws Exception { 330 Path src = base.resolve("src"); 331 332 tb.writeJavaFiles(src, 333 "package test; public class Test {}"); 334 335 Path out = base.resolve("out"); 336 337 Files.createDirectories(out); 338 339 Path reg = base.resolve("reg"); 340 Path regFile = reg.resolve("META-INF").resolve("services").resolve(Plugin.class.getName()); 341 342 Files.createDirectories(regFile.getParent()); 343 344 try (OutputStream regOut = Files.newOutputStream(regFile)) { 345 regOut.write(PluginImpl.class.getName().getBytes()); 346 } 347 348 String processorPath = System.getProperty("test.class.path") + File.pathSeparator + reg.toString(); 349 350 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 351 Path testSource = src.resolve("test").resolve("Test.java"); 352 try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) { 353 com.sun.source.util.JavacTask task = 354 (com.sun.source.util.JavacTask) javaCompiler.getTask(null, 355 null, 356 d -> { throw new IllegalStateException(d.toString()); }, 357 Arrays.asList("--processor-path", processorPath, 358 "-processor", AP.class.getName(), 359 "-Xplugin:test"), 360 null, 361 fm.getJavaFileObjects(testSource)); 362 task.call(); 363 } 364 365 Main.compile(new String[] {"--processor-path", processorPath, 366 "-Xplugin:test", 367 testSource.toString()}); 368 } 369 370 public static class PluginImpl implements Plugin { 371 372 @Override getName()373 public String getName() { 374 return "test"; 375 } 376 377 @Override init(com.sun.source.util.JavacTask task, String... args)378 public void init(com.sun.source.util.JavacTask task, String... args) { 379 task.addTaskListener(new TaskListener() { 380 boolean wasEntered; 381 @Override 382 public void started(TaskEvent e) { 383 switch (e.getKind()) { 384 case COMPILATION: case PARSE: 385 shouldFail(e.getKind()); 386 break; 387 case ANNOTATION_PROCESSING: case ENTER: 388 if (wasEntered) { 389 shouldPass(e.getKind()); 390 } else { 391 shouldFail(e.getKind()); 392 } 393 break; 394 default: 395 shouldPass(e.getKind()); 396 break; 397 } 398 } 399 @Override 400 public void finished(TaskEvent e) { 401 switch (e.getKind()) { 402 case PARSE: 403 shouldFail(e.getKind()); 404 break; 405 case ENTER: 406 wasEntered = true; 407 //fall-through: 408 default: 409 shouldPass(e.getKind()); 410 break; 411 } 412 } 413 private void shouldFail(TaskEvent.Kind kind) { 414 try { 415 task.getElements().getTypeElement("java.lang.String"); 416 throw new AssertionError("Expected exception not observed; kind=" + kind.name()); 417 } catch (IllegalStateException ex) { 418 //correct 419 } 420 } 421 private void shouldPass(TaskEvent.Kind kind) { 422 assertNotNull(task.getElements().getTypeElement("java.lang.String")); 423 } 424 }); 425 426 } 427 428 } 429 430 @SupportedAnnotationTypes("*") 431 public static final class AP extends AbstractProcessor { 432 433 @Override process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)434 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 435 return false; 436 } 437 438 @Override getSupportedSourceVersion()439 public SourceVersion getSupportedSourceVersion() { 440 return SourceVersion.latest(); 441 } 442 443 } 444 445 @Test testBrokenModule(Path base)446 public void testBrokenModule(Path base) throws Exception { 447 Map<String, String> sourceFileName2Content = new HashMap<>(); 448 449 sourceFileName2Content.put("module-info.java", "module test { requires unknown.; } "); 450 sourceFileName2Content.put("test/Test.java", "package test; public class Test {}"); 451 452 Path out = base.resolve("out"); 453 454 Files.createDirectories(out); 455 456 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 457 try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) { 458 com.sun.source.util.JavacTask task = 459 (com.sun.source.util.JavacTask) javaCompiler.getTask(null, 460 new TestMemoryFileManager(fm, sourceFileName2Content), 461 null, 462 Arrays.asList("-d", out.toString()), 463 null, 464 null); 465 task.getElements().getTypeElement("test.Test"); 466 } 467 } 468 469 private static final class TestMemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> { 470 471 private final Map<String, String> sourceFileName2Content; 472 TestMemoryFileManager(JavaFileManager fileManager, Map<String, String> sourceFileName2Content)473 public TestMemoryFileManager(JavaFileManager fileManager, Map<String, String> sourceFileName2Content) { 474 super(fileManager); 475 this.sourceFileName2Content = sourceFileName2Content; 476 } 477 478 @Override list(Location location, String packageName, Set<Kind> kinds, boolean recurse)479 public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException { 480 if (location == StandardLocation.SOURCE_PATH) { 481 List<JavaFileObject> result = new ArrayList<>(); 482 String dir = packageName.replace('.', '/') + "/"; 483 484 for (Entry<String, String> e : sourceFileName2Content.entrySet()) { 485 if (e.getKey().startsWith(dir) && 486 !e.getKey().substring(dir.length()).contains("/")) { 487 try { 488 result.add(new SourceFileObject(e.getKey(), e.getValue())); 489 } catch (URISyntaxException ex) { 490 throw new IOException(ex); 491 } 492 } 493 } 494 495 return result; 496 } 497 return super.list(location, packageName, kinds, recurse); 498 } 499 500 @Override getJavaFileForInput(Location location, String className, Kind kind)501 public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { 502 if (location == StandardLocation.SOURCE_PATH) { 503 String path = className.replace('.', '/') + ".java"; 504 String code = sourceFileName2Content.get(path); 505 506 if (code == null) return null; 507 508 try { 509 return new SourceFileObject(path, code); 510 } catch (URISyntaxException ex) { 511 throw new IOException(ex); 512 } 513 } 514 return super.getJavaFileForInput(location, className, kind); 515 } 516 517 @Override hasLocation(Location location)518 public boolean hasLocation(Location location) { 519 return super.hasLocation(location) || location == StandardLocation.SOURCE_PATH; 520 } 521 522 @Override contains(Location location, FileObject fo)523 public boolean contains(Location location, FileObject fo) throws IOException { 524 if (location == StandardLocation.SOURCE_PATH) { 525 return fo instanceof SourceFileObject; 526 } 527 return super.contains(location, fo); 528 } 529 530 @Override inferBinaryName(Location location, JavaFileObject file)531 public String inferBinaryName(Location location, JavaFileObject file) { 532 if (location == StandardLocation.SOURCE_PATH) { 533 String path = ((SourceFileObject) file).path; 534 String fileName = path.substring(path.lastIndexOf('/')); 535 return fileName.substring(0, fileName.length() - ".java".length()); 536 } 537 return super.inferBinaryName(location, file); 538 } 539 540 } 541 542 private static final class SourceFileObject extends SimpleJavaFileObject { 543 private final String path; 544 private final String code; 545 SourceFileObject(String path, String code)546 public SourceFileObject(String path, String code) throws URISyntaxException { 547 super(new URI("mem://" + path), Kind.SOURCE); 548 this.path = path; 549 this.code = code; 550 } 551 552 @Override getCharContent(boolean ignoreEncodingErrors)553 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { 554 return code; 555 } 556 557 @Override isNameCompatible(String simpleName, Kind kind)558 public boolean isNameCompatible(String simpleName, Kind kind) { 559 return path.endsWith(simpleName + kind.extension); 560 } 561 562 } 563 assertNotNull(Object actual)564 private static void assertNotNull(Object actual) { 565 if (actual == null) { 566 throw new AssertionError("unexpected null!"); 567 } 568 } 569 assertNull(Object actual)570 private static void assertNull(Object actual) { 571 if (actual != null) { 572 throw new AssertionError("unexpected non null!"); 573 } 574 } 575 576 } 577