AnnotationProcessing.java revision 3954:dee2b0b32d77
1184610Salfred/* 2184610Salfred * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3184610Salfred * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4184610Salfred * 5184610Salfred * This code is free software; you can redistribute it and/or modify it 6184610Salfred * under the terms of the GNU General Public License version 2 only, as 7184610Salfred * published by the Free Software Foundation. 8184610Salfred * 9184610Salfred * This code is distributed in the hope that it will be useful, but WITHOUT 10184610Salfred * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11184610Salfred * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12184610Salfred * version 2 for more details (a copy is included in the LICENSE file that 13184610Salfred * accompanied this code). 14184610Salfred * 15184610Salfred * You should have received a copy of the GNU General Public License version 16184610Salfred * 2 along with this work; if not, write to the Free Software Foundation, 17184610Salfred * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18184610Salfred * 19184610Salfred * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20184610Salfred * or visit www.oracle.com if you need additional information or have any 21184610Salfred * questions. 22184610Salfred */ 23184610Salfred 24184610Salfred/** 25184610Salfred * @test 26184610Salfred * @bug 8133884 8162711 8133896 8172158 8172262 8173636 27184610Salfred * @summary Verify that annotation processing works. 28184610Salfred * @library /tools/lib 29184610Salfred * @modules 30193640Sariff * jdk.compiler/com.sun.tools.javac.api 31193640Sariff * jdk.compiler/com.sun.tools.javac.main 32193640Sariff * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase 33193640Sariff * @run main AnnotationProcessing 34184610Salfred */ 35184610Salfred 36188957Sthompsaimport java.io.File; 37184610Salfredimport java.io.IOException; 38184610Salfredimport java.io.OutputStream; 39184610Salfredimport java.io.Reader; 40184610Salfredimport java.io.Writer; 41184610Salfredimport java.nio.file.Files; 42184610Salfredimport java.nio.file.Path; 43184610Salfredimport java.nio.file.Paths; 44184610Salfredimport java.util.Arrays; 45184610Salfredimport java.util.HashMap; 46184610Salfredimport java.util.HashSet; 47184610Salfredimport java.util.List; 48184610Salfredimport java.util.Map; 49184610Salfredimport java.util.Objects; 50184610Salfredimport java.util.Set; 51184610Salfredimport java.util.concurrent.Callable; 52184610Salfredimport java.util.function.Function; 53184610Salfredimport java.util.regex.Pattern; 54184610Salfredimport java.util.stream.Collectors; 55184610Salfred 56184610Salfredimport javax.annotation.processing.AbstractProcessor; 57184610Salfredimport javax.annotation.processing.Filer; 58184610Salfredimport javax.annotation.processing.FilerException; 59184610Salfredimport javax.annotation.processing.Messager; 60184610Salfredimport javax.annotation.processing.ProcessingEnvironment; 61184610Salfredimport javax.annotation.processing.RoundEnvironment; 62184610Salfredimport javax.annotation.processing.SupportedAnnotationTypes; 63193640Sariffimport javax.annotation.processing.SupportedOptions; 64184610Salfredimport javax.lang.model.SourceVersion; 65184610Salfredimport javax.lang.model.element.Element; 66184610Salfredimport javax.lang.model.element.ElementKind; 67184610Salfredimport javax.lang.model.element.ModuleElement; 68184610Salfredimport javax.lang.model.element.ModuleElement.ProvidesDirective; 69193640Sariffimport javax.lang.model.element.ModuleElement.UsesDirective; 70184610Salfredimport javax.lang.model.element.PackageElement; 71184610Salfredimport javax.lang.model.element.TypeElement; 72184610Salfredimport javax.lang.model.element.VariableElement; 73184610Salfredimport javax.lang.model.type.TypeKind; 74184610Salfredimport javax.lang.model.util.ElementFilter; 75184610Salfredimport javax.lang.model.util.ElementScanner9; 76184610Salfredimport javax.tools.Diagnostic.Kind; 77184610Salfredimport javax.tools.FileObject; 78184610Salfredimport javax.tools.JavaCompiler; 79184610Salfredimport javax.tools.JavaCompiler.CompilationTask; 80184610Salfredimport javax.tools.JavaFileManager; 81184610Salfredimport javax.tools.JavaFileManager.Location; 82184610Salfredimport javax.tools.JavaFileObject; 83184610Salfredimport javax.tools.StandardJavaFileManager; 84184610Salfredimport javax.tools.StandardLocation; 85184610Salfredimport javax.tools.ToolProvider; 86184610Salfred 87184610Salfredimport toolbox.JavacTask; 88184610Salfredimport toolbox.Task; 89184610Salfredimport toolbox.Task.Mode; 90184610Salfredimport toolbox.Task.OutputKind; 91184610Salfred 92184610Salfredpublic class AnnotationProcessing extends ModuleTestBase { 93184610Salfred 94193640Sariff public static void main(String... args) throws Exception { 95184610Salfred new AnnotationProcessing().runTests(); 96184610Salfred } 97184610Salfred 98184610Salfred @Test 99184610Salfred public void testAPSingleModule(Path base) throws Exception { 100184610Salfred Path moduleSrc = base.resolve("module-src"); 101184610Salfred Path m1 = moduleSrc.resolve("m1x"); 102184610Salfred 103184610Salfred Path classes = base.resolve("classes"); 104184610Salfred 105184610Salfred Files.createDirectories(classes); 106193640Sariff 107193640Sariff tb.writeJavaFiles(m1, 108193640Sariff "module m1x { }", 109193640Sariff "package impl; public class Impl { }"); 110193640Sariff 111193640Sariff String log = new JavacTask(tb) 112184610Salfred .options("--module-source-path", moduleSrc.toString(), 113184610Salfred "-processor", AP.class.getName(), 114184610Salfred "-AexpectedEnclosedElements=m1x=>impl") 115184610Salfred .outdir(classes) 116184610Salfred .files(findJavaFiles(moduleSrc)) 117184610Salfred .run() 118184610Salfred .writeAll() 119184610Salfred .getOutput(Task.OutputKind.DIRECT); 120184610Salfred 121184610Salfred if (!log.isEmpty()) 122193640Sariff throw new AssertionError("Unexpected output: " + log); 123193640Sariff } 124184610Salfred 125184610Salfred @Test 126184610Salfred public void testAPMultiModule(Path base) throws Exception { 127184610Salfred Path moduleSrc = base.resolve("module-src"); 128184610Salfred Path m1 = moduleSrc.resolve("m1x"); 129184610Salfred Path m2 = moduleSrc.resolve("m2x"); 130184610Salfred 131184610Salfred Path classes = base.resolve("classes"); 132184610Salfred 133184610Salfred Files.createDirectories(classes); 134184610Salfred 135184610Salfred tb.writeJavaFiles(m1, 136184610Salfred "module m1x { }", 137184610Salfred "package impl1; public class Impl1 { }"); 138184610Salfred 139184610Salfred tb.writeJavaFiles(m2, 140184610Salfred "module m2x { }", 141184610Salfred "package impl2; public class Impl2 { }"); 142184610Salfred 143184610Salfred String log = new JavacTask(tb) 144184610Salfred .options("--module-source-path", moduleSrc.toString(), 145184610Salfred "-processor", AP.class.getName(), 146184610Salfred "-AexpectedEnclosedElements=m1x=>impl1,m2x=>impl2") 147184610Salfred .outdir(classes) 148184610Salfred .files(findJavaFiles(moduleSrc)) 149184610Salfred .run() 150184610Salfred .writeAll() 151184610Salfred .getOutput(Task.OutputKind.DIRECT); 152184610Salfred 153184610Salfred if (!log.isEmpty()) 154193640Sariff throw new AssertionError("Unexpected output: " + log); 155184610Salfred } 156184610Salfred 157184610Salfred @SupportedAnnotationTypes("*") 158184610Salfred @SupportedOptions("expectedEnclosedElements") 159184610Salfred public static final class AP extends AbstractProcessor { 160184610Salfred 161184610Salfred private Map<String, List<String>> module2ExpectedEnclosedElements; 162184610Salfred private Set<String> seenModules = new HashSet<>(); 163184610Salfred 164184610Salfred @Override 165184610Salfred public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 166184610Salfred if (module2ExpectedEnclosedElements == null) { 167184610Salfred module2ExpectedEnclosedElements = new HashMap<>(); 168184610Salfred 169184610Salfred String expectedEnclosedElements = 170184610Salfred processingEnv.getOptions().get("expectedEnclosedElements"); 171184610Salfred 172184610Salfred for (String moduleDef : expectedEnclosedElements.split(",")) { 173184610Salfred String[] module2Packages = moduleDef.split("=>"); 174184610Salfred 175184610Salfred module2ExpectedEnclosedElements.put(module2Packages[0], 176184610Salfred List.of(module2Packages[1].split(":"))); 177184610Salfred } 178184610Salfred } 179184610Salfred 180184610Salfred //verify ModuleType and ModuleSymbol behavior: 181184610Salfred for (Element root : roundEnv.getRootElements()) { 182184610Salfred ModuleElement module = processingEnv.getElementUtils().getModuleOf(root); 183184610Salfred 184184610Salfred assertEquals(TypeKind.MODULE, module.asType().getKind()); 185193640Sariff 186184610Salfred boolean[] seenModule = new boolean[1]; 187184610Salfred 188184610Salfred module.accept(new ElementScanner9<Void, Void>() { 189184610Salfred @Override 190184610Salfred public Void visitModule(ModuleElement e, Void p) { 191184610Salfred seenModule[0] = true; 192184610Salfred return null; 193184610Salfred } 194184610Salfred @Override 195184610Salfred public Void scan(Element e, Void p) { 196184610Salfred throw new AssertionError("Shouldn't get here."); 197184610Salfred } 198184610Salfred }, null); 199184610Salfred 200184610Salfred assertEquals(true, seenModule[0]); 201184610Salfred 202184610Salfred List<String> actualElements = 203184610Salfred module.getEnclosedElements() 204184610Salfred .stream() 205184610Salfred .map(s -> (PackageElement) s) 206184610Salfred .map(p -> p.getQualifiedName().toString()) 207184610Salfred .collect(Collectors.toList()); 208184610Salfred 209184610Salfred String moduleName = module.getQualifiedName().toString(); 210184610Salfred 211184610Salfred assertEquals(module2ExpectedEnclosedElements.get(moduleName), 212184610Salfred actualElements); 213184610Salfred 214184610Salfred seenModules.add(moduleName); 215184610Salfred } 216184610Salfred 217184610Salfred if (roundEnv.processingOver()) { 218184610Salfred assertEquals(module2ExpectedEnclosedElements.keySet(), seenModules); 219184610Salfred } 220184610Salfred 221184610Salfred return false; 222184610Salfred } 223184610Salfred 224184610Salfred @Override 225184610Salfred public SourceVersion getSupportedSourceVersion() { 226184610Salfred return SourceVersion.latest(); 227184610Salfred } 228184610Salfred 229184610Salfred } 230184610Salfred 231184610Salfred @Test 232184610Salfred public void testVerifyUsesProvides(Path base) throws Exception { 233184610Salfred Path moduleSrc = base.resolve("module-src"); 234184610Salfred Path m1 = moduleSrc.resolve("m1x"); 235184610Salfred 236184610Salfred Path classes = base.resolve("classes"); 237184610Salfred 238184610Salfred Files.createDirectories(classes); 239184610Salfred 240184610Salfred tb.writeJavaFiles(m1, 241184610Salfred "module m1x { exports api; uses api.Api; provides api.Api with impl.Impl; }", 242184610Salfred "package api; public class Api { }", 243 "package impl; public class Impl extends api.Api { }"); 244 245 String log = new JavacTask(tb) 246 .options("-doe", "-processor", VerifyUsesProvidesAP.class.getName()) 247 .outdir(classes) 248 .files(findJavaFiles(moduleSrc)) 249 .run() 250 .writeAll() 251 .getOutput(Task.OutputKind.DIRECT); 252 253 if (!log.isEmpty()) 254 throw new AssertionError("Unexpected output: " + log); 255 } 256 257 @SupportedAnnotationTypes("*") 258 public static final class VerifyUsesProvidesAP extends AbstractProcessor { 259 260 @Override 261 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 262 TypeElement api = processingEnv.getElementUtils().getTypeElement("api.Api"); 263 264 assertNonNull("Cannot find api.Api", api); 265 266 ModuleElement modle = (ModuleElement) processingEnv.getElementUtils().getPackageOf(api).getEnclosingElement(); 267 268 assertNonNull("modle is null", modle); 269 270 List<? extends UsesDirective> uses = ElementFilter.usesIn(modle.getDirectives()); 271 assertEquals(1, uses.size()); 272 assertEquals("api.Api", uses.iterator().next().getService().getQualifiedName().toString()); 273 274 List<? extends ProvidesDirective> provides = ElementFilter.providesIn(modle.getDirectives()); 275 assertEquals(1, provides.size()); 276 assertEquals("api.Api", provides.iterator().next().getService().getQualifiedName().toString()); 277 assertEquals("impl.Impl", provides.iterator().next().getImplementations().get(0).getQualifiedName().toString()); 278 279 return false; 280 } 281 282 @Override 283 public SourceVersion getSupportedSourceVersion() { 284 return SourceVersion.latest(); 285 } 286 287 } 288 289 @Test 290 public void testPackageNoModule(Path base) throws Exception { 291 Path src = base.resolve("src"); 292 Path classes = base.resolve("classes"); 293 294 Files.createDirectories(classes); 295 296 tb.writeJavaFiles(src, 297 "package api; public class Api { }"); 298 299 String log = new JavacTask(tb) 300 .options("-processor", VerifyPackageNoModule.class.getName(), 301 "-source", "8", 302 "-Xlint:-options") 303 .outdir(classes) 304 .files(findJavaFiles(src)) 305 .run() 306 .writeAll() 307 .getOutput(Task.OutputKind.DIRECT); 308 309 if (!log.isEmpty()) 310 throw new AssertionError("Unexpected output: " + log); 311 } 312 313 @SupportedAnnotationTypes("*") 314 public static final class VerifyPackageNoModule extends AbstractProcessor { 315 316 @Override 317 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 318 TypeElement api = processingEnv.getElementUtils().getTypeElement("api.Api"); 319 320 assertNonNull("Cannot find api.Api", api); 321 322 ModuleElement modle = (ModuleElement) processingEnv.getElementUtils().getPackageOf(api).getEnclosingElement(); 323 324 assertNull("modle is not null", modle); 325 326 return false; 327 } 328 329 @Override 330 public SourceVersion getSupportedSourceVersion() { 331 return SourceVersion.latest(); 332 } 333 334 } 335 336 @Test 337 public void testQualifiedClassForProcessing(Path base) throws Exception { 338 Path moduleSrc = base.resolve("module-src"); 339 Path m1 = moduleSrc.resolve("m1x"); 340 Path m2 = moduleSrc.resolve("m2x"); 341 342 Path classes = base.resolve("classes"); 343 344 Files.createDirectories(classes); 345 346 tb.writeJavaFiles(m1, 347 "module m1x { }", 348 "package impl; public class Impl { int m1x; }"); 349 350 tb.writeJavaFiles(m2, 351 "module m2x { }", 352 "package impl; public class Impl { int m2x; }"); 353 354 new JavacTask(tb) 355 .options("--module-source-path", moduleSrc.toString()) 356 .outdir(classes) 357 .files(findJavaFiles(moduleSrc)) 358 .run() 359 .writeAll() 360 .getOutput(Task.OutputKind.DIRECT); 361 362 List<String> expected = List.of("Note: field: m1x"); 363 364 for (Mode mode : new Mode[] {Mode.API, Mode.CMDLINE}) { 365 List<String> log = new JavacTask(tb, mode) 366 .options("-processor", QualifiedClassForProcessing.class.getName(), 367 "--module-path", classes.toString()) 368 .classes("m1x/impl.Impl") 369 .outdir(classes) 370 .run() 371 .writeAll() 372 .getOutputLines(Task.OutputKind.DIRECT); 373 374 if (!expected.equals(log)) 375 throw new AssertionError("Unexpected output: " + log); 376 } 377 } 378 379 @SupportedAnnotationTypes("*") 380 public static final class QualifiedClassForProcessing extends AbstractProcessor { 381 382 @Override 383 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 384 if (processingEnv.getElementUtils().getModuleElement("m1x") == null) { 385 throw new AssertionError("No m1x module found."); 386 } 387 388 Messager messager = processingEnv.getMessager(); 389 390 for (TypeElement clazz : ElementFilter.typesIn(roundEnv.getRootElements())) { 391 for (VariableElement field : ElementFilter.fieldsIn(clazz.getEnclosedElements())) { 392 messager.printMessage(Kind.NOTE, "field: " + field.getSimpleName()); 393 } 394 } 395 396 return false; 397 } 398 399 @Override 400 public SourceVersion getSupportedSourceVersion() { 401 return SourceVersion.latest(); 402 } 403 404 } 405 406 @Test 407 public void testModuleInRootElements(Path base) throws Exception { 408 Path moduleSrc = base.resolve("module-src"); 409 Path m1 = moduleSrc.resolve("m1"); 410 411 Path classes = base.resolve("classes"); 412 413 Files.createDirectories(classes); 414 415 tb.writeJavaFiles(m1, 416 "module m1x { exports api; }", 417 "package api; public class Api { }"); 418 419 List<String> log = new JavacTask(tb) 420 .options("-processor", ModuleInRootElementsAP.class.getName()) 421 .outdir(classes) 422 .files(findJavaFiles(moduleSrc)) 423 .run() 424 .writeAll() 425 .getOutputLines(Task.OutputKind.STDERR); 426 427 assertEquals(List.of("module: m1x"), log); 428 } 429 430 @SupportedAnnotationTypes("*") 431 public static final class ModuleInRootElementsAP extends AbstractProcessor { 432 433 @Override 434 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 435 roundEnv.getRootElements() 436 .stream() 437 .filter(el -> el.getKind() == ElementKind.MODULE) 438 .forEach(mod -> System.err.println("module: " + mod.getSimpleName())); 439 440 return false; 441 } 442 443 @Override 444 public SourceVersion getSupportedSourceVersion() { 445 return SourceVersion.latest(); 446 } 447 448 } 449 450 @Test 451 public void testAnnotationsInModuleInfo(Path base) throws Exception { 452 Path moduleSrc = base.resolve("module-src"); 453 Path m1 = moduleSrc.resolve("m1"); 454 455 tb.writeJavaFiles(m1, 456 "@Deprecated module m1x { }"); 457 458 Path m2 = moduleSrc.resolve("m2x"); 459 460 tb.writeJavaFiles(m2, 461 "@SuppressWarnings(\"\") module m2x { }"); 462 463 Path classes = base.resolve("classes"); 464 465 Files.createDirectories(classes); 466 467 List<String> log = new JavacTask(tb) 468 .options("-processor", AnnotationsInModuleInfoPrint.class.getName()) 469 .outdir(classes) 470 .files(findJavaFiles(m1)) 471 .run() 472 .writeAll() 473 .getOutputLines(Task.OutputKind.DIRECT); 474 475 List<String> expectedLog = List.of("Note: AP Invoked", 476 "Note: AP Invoked"); 477 478 assertEquals(expectedLog, log); 479 480 new JavacTask(tb) 481 .options("-processor", AnnotationsInModuleInfoFail.class.getName()) 482 .outdir(classes) 483 .files(findJavaFiles(m2)) 484 .run() 485 .writeAll(); 486 } 487 488 @SupportedAnnotationTypes("java.lang.Deprecated") 489 public static final class AnnotationsInModuleInfoPrint extends AbstractProcessor { 490 491 @Override 492 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 493 processingEnv.getMessager().printMessage(Kind.NOTE, "AP Invoked"); 494 return false; 495 } 496 497 @Override 498 public SourceVersion getSupportedSourceVersion() { 499 return SourceVersion.latest(); 500 } 501 502 } 503 504 @SupportedAnnotationTypes("java.lang.Deprecated") 505 public static final class AnnotationsInModuleInfoFail extends AbstractProcessor { 506 507 @Override 508 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 509 throw new AssertionError(); 510 } 511 512 @Override 513 public SourceVersion getSupportedSourceVersion() { 514 return SourceVersion.latest(); 515 } 516 517 } 518 519 @Test 520 public void testGenerateInMultiModeAPI(Path base) throws Exception { 521 Path moduleSrc = base.resolve("module-src"); 522 Path classes = base.resolve("classes"); 523 524 Files.createDirectories(classes); 525 526 Path m1 = moduleSrc.resolve("m1x"); 527 528 tb.writeJavaFiles(m1, 529 "module m1x { exports api1; }", 530 "package api1; public class Api { GenApi ga; impl.Impl i; }"); 531 532 writeFile("1", m1, "api1", "api"); 533 writeFile("1", m1, "impl", "impl"); 534 535 Path m2 = moduleSrc.resolve("m2x"); 536 537 tb.writeJavaFiles(m2, 538 "module m2x { requires m1x; exports api2; }", 539 "package api2; public class Api { api1.GenApi ga1; GenApi qa2; impl.Impl i;}"); 540 541 writeFile("2", m2, "api2", "api"); 542 writeFile("2", m2, "impl", "impl"); 543 544 for (FileType fileType : FileType.values()) { 545 if (Files.isDirectory(classes)) { 546 tb.cleanDirectory(classes); 547 } else { 548 Files.createDirectories(classes); 549 } 550 551 new JavacTask(tb) 552 .options("-processor", MultiModeAPITestAP.class.getName(), 553 "--module-source-path", moduleSrc.toString(), 554 "-Afiletype=" + fileType.name()) 555 .outdir(classes) 556 .files(findJavaFiles(moduleSrc)) 557 .run() 558 .writeAll(); 559 560 assertFileExists(classes, "m1x", "api1", "GenApi.class"); 561 assertFileExists(classes, "m1x", "impl", "Impl.class"); 562 assertFileExists(classes, "m1x", "api1", "gen1"); 563 assertFileExists(classes, "m2x", "api2", "GenApi.class"); 564 assertFileExists(classes, "m2x", "impl", "Impl.class"); 565 assertFileExists(classes, "m2x", "api2", "gen1"); 566 } 567 } 568 569 enum FileType { 570 SOURCE, 571 CLASS; 572 } 573 574 public static abstract class GeneratingAP extends AbstractProcessor { 575 576 void createSource(CreateFileObject file, String name, String content) { 577 try (Writer out = file.create().openWriter()) { 578 out.write(content); 579 } catch (IOException ex) { 580 throw new IllegalStateException(ex); 581 } 582 } 583 584 void createClass(CreateFileObject file, String name, String content) { 585 String fileNameStub = name.replace(".", File.separator); 586 587 try (OutputStream out = file.create().openOutputStream()) { 588 Path scratch = Files.createDirectories(Paths.get("")); 589 Path scratchSrc = scratch.resolve(fileNameStub + ".java").toAbsolutePath(); 590 591 Files.createDirectories(scratchSrc.getParent()); 592 593 try (Writer w = Files.newBufferedWriter(scratchSrc)) { 594 w.write(content); 595 } 596 597 Path scratchClasses = scratch.resolve("classes"); 598 599 Files.createDirectories(scratchClasses); 600 601 JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 602 try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) { 603 List<String> options = List.of("-d", scratchClasses.toString()); 604 Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(scratchSrc); 605 CompilationTask task = comp.getTask(null, fm, null, options, null, files); 606 607 if (!task.call()) { 608 throw new AssertionError("compilation failed"); 609 } 610 } 611 612 Path classfile = scratchClasses.resolve(fileNameStub + ".class"); 613 614 Files.copy(classfile, out); 615 } catch (IOException ex) { 616 throw new IllegalStateException(ex); 617 } 618 } 619 620 void doReadResource(CreateFileObject file, String expectedContent) { 621 try { 622 StringBuilder actualContent = new StringBuilder(); 623 624 try (Reader r = file.create().openReader(true)) { 625 int read; 626 627 while ((read = r.read()) != (-1)) { 628 actualContent.append((char) read); 629 } 630 631 } 632 633 assertEquals(expectedContent, actualContent.toString()); 634 } catch (IOException ex) { 635 throw new IllegalStateException(ex); 636 } 637 } 638 639 public interface CreateFileObject { 640 public FileObject create() throws IOException; 641 } 642 643 void expectFilerException(Callable<Object> c) { 644 try { 645 c.call(); 646 throw new AssertionError("Expected exception not thrown"); 647 } catch (FilerException ex) { 648 //expected 649 } catch (Exception ex) { 650 throw new IllegalStateException(ex); 651 } 652 } 653 654 @Override 655 public SourceVersion getSupportedSourceVersion() { 656 return SourceVersion.latest(); 657 } 658 659 } 660 661 @SupportedAnnotationTypes("*") 662 @SupportedOptions({"filetype", "modulename"}) 663 public static final class MultiModeAPITestAP extends GeneratingAP { 664 665 int round; 666 667 @Override 668 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 669 if (round++ != 0) 670 return false; 671 672 createClass("m1x", "api1.GenApi", "package api1; public class GenApi {}"); 673 createClass("m1x", "impl.Impl", "package impl; public class Impl {}"); 674 createClass("m2x", "api2.GenApi", "package api2; public class GenApi {}"); 675 createClass("m2x", "impl.Impl", "package impl; public class Impl {}"); 676 677 createResource("m1x", "api1", "gen1"); 678 createResource("m2x", "api2", "gen1"); 679 680 readResource("m1x", "api1", "api", "1"); 681 readResource("m1x", "impl", "impl", "1"); 682 readResource("m2x", "api2", "api", "2"); 683 readResource("m2x", "impl", "impl", "2"); 684 685 Filer filer = processingEnv.getFiler(); 686 687 expectFilerException(() -> filer.createSourceFile("fail.Fail")); 688 expectFilerException(() -> filer.createClassFile("fail.Fail")); 689 expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "fail", "fail")); 690 expectFilerException(() -> filer.getResource(StandardLocation.MODULE_SOURCE_PATH, "fail", "fail")); 691 692 //must not generate to unnamed package: 693 expectFilerException(() -> filer.createSourceFile("m1/Fail")); 694 expectFilerException(() -> filer.createClassFile("m1/Fail")); 695 696 //cannot generate resources to modules that are not root modules: 697 expectFilerException(() -> filer.createSourceFile("java.base/fail.Fail")); 698 expectFilerException(() -> filer.createClassFile("java.base/fail.Fail")); 699 expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "java.base/fail", "Fail")); 700 701 return false; 702 } 703 704 void createClass(String expectedModule, String name, String content) { 705 Filer filer = processingEnv.getFiler(); 706 FileType filetype = FileType.valueOf(processingEnv.getOptions().getOrDefault("filetype", "")); 707 708 switch (filetype) { 709 case SOURCE: 710 createSource(() -> filer.createSourceFile(expectedModule + "/" + name), name, content); 711 break; 712 case CLASS: 713 createClass(() -> filer.createClassFile(expectedModule + "/" + name), name, content); 714 break; 715 default: 716 throw new AssertionError("Unexpected filetype: " + filetype); 717 } 718 } 719 720 void createResource(String expectedModule, String pkg, String relName) { 721 try { 722 Filer filer = processingEnv.getFiler(); 723 724 filer.createResource(StandardLocation.CLASS_OUTPUT, expectedModule + "/" + pkg, relName) 725 .openOutputStream() 726 .close(); 727 } catch (IOException ex) { 728 throw new IllegalStateException(ex); 729 } 730 } 731 732 void readResource(String expectedModule, String pkg, String relName, String expectedContent) { 733 Filer filer = processingEnv.getFiler(); 734 735 doReadResource(() -> filer.getResource(StandardLocation.MODULE_SOURCE_PATH, expectedModule + "/" + pkg, relName), 736 expectedContent); 737 } 738 739 } 740 741 @Test 742 public void testGenerateInSingleNameModeAPI(Path base) throws Exception { 743 Path classes = base.resolve("classes"); 744 745 Files.createDirectories(classes); 746 747 Path m1 = base.resolve("module-src"); 748 749 tb.writeJavaFiles(m1, 750 "module m1x { }"); 751 752 writeFile("3", m1, "impl", "resource"); 753 754 new JavacTask(tb) 755 .options("-processor", SingleNameModeAPITestAP.class.getName(), 756 "-sourcepath", m1.toString()) 757 .outdir(classes) 758 .files(findJavaFiles(m1)) 759 .run() 760 .writeAll(); 761 762 assertFileExists(classes, "impl", "Impl1.class"); 763 assertFileExists(classes, "impl", "Impl2.class"); 764 assertFileExists(classes, "impl", "Impl3"); 765 assertFileExists(classes, "impl", "Impl4.class"); 766 assertFileExists(classes, "impl", "Impl5.class"); 767 assertFileExists(classes, "impl", "Impl6"); 768 assertFileExists(classes, "impl", "Impl7.class"); 769 assertFileExists(classes, "impl", "Impl8.class"); 770 assertFileExists(classes, "impl", "Impl9"); 771 } 772 773 774 @SupportedAnnotationTypes("*") 775 public static final class SingleNameModeAPITestAP extends GeneratingAP { 776 777 int round; 778 779 @Override 780 public synchronized void init(ProcessingEnvironment processingEnv) { 781 super.init(processingEnv); 782 } 783 784 @Override 785 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 786 if (round++ != 0) 787 return false; 788 789 Filer filer = processingEnv.getFiler(); 790 791 createSource(() -> filer.createSourceFile("impl.Impl1"), "impl.Impl1", "package impl; class Impl1 {}"); 792 createClass(() -> filer.createClassFile("impl.Impl2"), "impl.Impl2", "package impl; class Impl2 {}"); 793 createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "impl", "Impl3"), "impl.Impl3", ""); 794 doReadResource(() -> filer.getResource(StandardLocation.SOURCE_PATH, "impl", "resource"), "3"); 795 796 createSource(() -> filer.createSourceFile("m1x/impl.Impl4"), "impl.Impl4", "package impl; class Impl4 {}"); 797 createClass(() -> filer.createClassFile("m1x/impl.Impl5"), "impl.Impl5", "package impl; class Impl5 {}"); 798 createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "m1x/impl", "Impl6"), "impl.Impl6", ""); 799 doReadResource(() -> filer.getResource(StandardLocation.SOURCE_PATH, "m1x/impl", "resource"), "3"); 800 801 TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object"); 802 803 //"broken" originating element: 804 createSource(() -> filer.createSourceFile("impl.Impl7", jlObject), "impl.Impl7", "package impl; class Impl7 {}"); 805 createClass(() -> filer.createClassFile("impl.Impl8", jlObject), "impl.Impl8", "package impl; class Impl8 {}"); 806 createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "impl", "Impl9", jlObject), "impl.Impl9", ""); 807 808 //must not generate to unnamed package: 809 expectFilerException(() -> filer.createSourceFile("Fail")); 810 expectFilerException(() -> filer.createClassFile("Fail")); 811 expectFilerException(() -> filer.createSourceFile("m1x/Fail")); 812 expectFilerException(() -> filer.createClassFile("m1x/Fail")); 813 814 //cannot generate resources to modules that are not root modules: 815 expectFilerException(() -> filer.createSourceFile("java.base/fail.Fail")); 816 expectFilerException(() -> filer.createClassFile("java.base/fail.Fail")); 817 expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "java.base/fail", "Fail")); 818 819 return false; 820 } 821 822 } 823 824 @Test 825 public void testGenerateInUnnamedModeAPI(Path base) throws Exception { 826 Path classes = base.resolve("classes"); 827 828 Files.createDirectories(classes); 829 830 Path src = base.resolve("src"); 831 832 tb.writeJavaFiles(src, 833 "class T {}"); 834 835 new JavacTask(tb) 836 .options("-processor", UnnamedModeAPITestAP.class.getName(), 837 "-sourcepath", src.toString()) 838 .outdir(classes) 839 .files(findJavaFiles(src)) 840 .run() 841 .writeAll(); 842 843 assertFileExists(classes, "Impl1.class"); 844 assertFileExists(classes, "Impl2.class"); 845 } 846 847 @Test 848 public void testGenerateInNoModeAPI(Path base) throws Exception { 849 Path classes = base.resolve("classes"); 850 851 Files.createDirectories(classes); 852 853 Path src = base.resolve("src"); 854 855 tb.writeJavaFiles(src, 856 "class T {}"); 857 858 new JavacTask(tb) 859 .options("-processor", UnnamedModeAPITestAP.class.getName(), 860 "-source", "8", "-target", "8", 861 "-sourcepath", src.toString()) 862 .outdir(classes) 863 .files(findJavaFiles(src)) 864 .run() 865 .writeAll(); 866 867 assertFileExists(classes, "Impl1.class"); 868 assertFileExists(classes, "Impl2.class"); 869 } 870 871 @SupportedAnnotationTypes("*") 872 public static final class UnnamedModeAPITestAP extends GeneratingAP { 873 874 int round; 875 876 @Override 877 public synchronized void init(ProcessingEnvironment processingEnv) { 878 super.init(processingEnv); 879 } 880 881 @Override 882 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 883 if (round++ != 0) 884 return false; 885 886 Filer filer = processingEnv.getFiler(); 887 888 //must not generate to unnamed package: 889 createSource(() -> filer.createSourceFile("Impl1"), "Impl1", "class Impl1 {}"); 890 createClass(() -> filer.createClassFile("Impl2"), "Impl2", "class Impl2 {}"); 891 892 return false; 893 } 894 895 } 896 897 @Test 898 public void testDisambiguateAnnotations(Path base) throws Exception { 899 Path classes = base.resolve("classes"); 900 901 Files.createDirectories(classes); 902 903 Path src = base.resolve("src"); 904 Path m1 = src.resolve("m1x"); 905 906 tb.writeJavaFiles(m1, 907 "module m1x { exports api; }", 908 "package api; public @interface A {}", 909 "package api; public @interface B {}"); 910 911 Path m2 = src.resolve("m2x"); 912 913 tb.writeJavaFiles(m2, 914 "module m2x { exports api; }", 915 "package api; public @interface A {}", 916 "package api; public @interface B {}"); 917 918 Path m3 = src.resolve("m3x"); 919 920 tb.writeJavaFiles(m3, 921 "module m3x { requires m1x; }", 922 "package impl; import api.*; @A @B public class T {}"); 923 924 Path m4 = src.resolve("m4x"); 925 926 tb.writeJavaFiles(m4, 927 "module m4x { requires m2x; }", 928 "package impl; import api.*; @A @B public class T {}"); 929 930 List<String> log; 931 List<String> expected; 932 933 log = new JavacTask(tb) 934 .options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(), 935 "--module-source-path", src.toString(), 936 "-m", "m1x,m2x") 937 .outdir(classes) 938 .run() 939 .writeAll() 940 .getOutputLines(OutputKind.STDERR); 941 942 expected = List.of(""); 943 944 if (!expected.equals(log)) { 945 throw new AssertionError("Output does not match; output: " + log); 946 } 947 948 log = new JavacTask(tb) 949 .options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(), 950 "--module-source-path", src.toString(), 951 "-m", "m3x") 952 .outdir(classes) 953 .run() 954 .writeAll() 955 .getOutputLines(OutputKind.STDERR); 956 957 expected = List.of("SelectAnnotationBTestAP", 958 "SelectAnnotationBTestAP"); 959 960 if (!expected.equals(log)) { 961 throw new AssertionError("Output does not match; output: " + log); 962 } 963 964 log = new JavacTask(tb) 965 .options("-processor", SelectAnnotationATestAP.class.getName() + "," + 966 SelectAnnotationBTestAP.class.getName() + "," + 967 SelectAnnotationAStrictTestAP.class.getName(), 968 "--module-source-path", src.toString(), 969 "-m", "m4x") 970 .outdir(classes) 971 .run() 972 .writeAll() 973 .getOutputLines(OutputKind.STDERR); 974 975 expected = List.of("SelectAnnotationATestAP", 976 "SelectAnnotationBTestAP", 977 "SelectAnnotationAStrictTestAP", 978 "SelectAnnotationATestAP", 979 "SelectAnnotationBTestAP", 980 "SelectAnnotationAStrictTestAP"); 981 982 if (!expected.equals(log)) { 983 throw new AssertionError("Output does not match; output: " + log); 984 } 985 } 986 987 @Test 988 public void testDisambiguateAnnotationsUnnamedModule(Path base) throws Exception { 989 Path classes = base.resolve("classes"); 990 991 Files.createDirectories(classes); 992 993 Path src = base.resolve("src"); 994 995 tb.writeJavaFiles(src, 996 "package api; public @interface A {}", 997 "package api; public @interface B {}", 998 "package impl; import api.*; @A @B public class T {}"); 999 1000 List<String> log = new JavacTask(tb) 1001 .options("-processor", SelectAnnotationATestAP.class.getName() + "," + 1002 SelectAnnotationBTestAP.class.getName() + "," + 1003 SelectAnnotationAStrictTestAP.class.getName()) 1004 .outdir(classes) 1005 .files(findJavaFiles(src)) 1006 .run() 1007 .writeAll() 1008 .getOutputLines(OutputKind.STDERR); 1009 1010 List<String> expected = List.of("SelectAnnotationBTestAP", 1011 "SelectAnnotationBTestAP"); 1012 1013 if (!expected.equals(log)) { 1014 throw new AssertionError("Output does not match; output: " + log); 1015 } 1016 } 1017 1018 @Test 1019 public void testDisambiguateAnnotationsNoModules(Path base) throws Exception { 1020 Path classes = base.resolve("classes"); 1021 1022 Files.createDirectories(classes); 1023 1024 Path src = base.resolve("src"); 1025 1026 tb.writeJavaFiles(src, 1027 "package api; public @interface A {}", 1028 "package api; public @interface B {}", 1029 "package impl; import api.*; @A @B public class T {}"); 1030 1031 List<String> log = new JavacTask(tb) 1032 .options("-processor", SelectAnnotationATestAP.class.getName() + "," + 1033 SelectAnnotationBTestAP.class.getName() + "," + 1034 SelectAnnotationAStrictTestAP.class.getName(), 1035 "-source", "8", "-target", "8") 1036 .outdir(classes) 1037 .files(findJavaFiles(src)) 1038 .run() 1039 .writeAll() 1040 .getOutputLines(OutputKind.STDERR); 1041 1042 List<String> expected = List.of("SelectAnnotationATestAP", 1043 "SelectAnnotationBTestAP", 1044 "SelectAnnotationATestAP", 1045 "SelectAnnotationBTestAP"); 1046 1047 if (!expected.equals(log)) { 1048 throw new AssertionError("Output does not match; output: " + log); 1049 } 1050 } 1051 1052 @SupportedAnnotationTypes("m2x/api.A") 1053 public static final class SelectAnnotationATestAP extends AbstractProcessor { 1054 1055 @Override 1056 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 1057 System.err.println("SelectAnnotationATestAP"); 1058 1059 return false; 1060 } 1061 1062 } 1063 1064 @SupportedAnnotationTypes("api.B") 1065 public static final class SelectAnnotationBTestAP extends AbstractProcessor { 1066 1067 @Override 1068 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 1069 System.err.println("SelectAnnotationBTestAP"); 1070 1071 return false; 1072 } 1073 1074 } 1075 1076 public static final class SelectAnnotationAStrictTestAP extends AbstractProcessor { 1077 1078 @Override 1079 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 1080 System.err.println("SelectAnnotationAStrictTestAP"); 1081 1082 return false; 1083 } 1084 1085 @Override 1086 public Set<String> getSupportedAnnotationTypes() { 1087 return Set.of("m2x/api.A"); 1088 } 1089 1090 } 1091 1092 private static void writeFile(String content, Path base, String... pathElements) throws IOException { 1093 Path file = resolveFile(base, pathElements); 1094 1095 Files.createDirectories(file.getParent()); 1096 1097 try (Writer out = Files.newBufferedWriter(file)) { 1098 out.append(content); 1099 } 1100 } 1101 1102 @Test 1103 public void testUnboundLookup(Path base) throws Exception { 1104 Path src = base.resolve("src"); 1105 1106 tb.writeJavaFiles(src, 1107 "package impl.conflict.src; public class Impl { }"); 1108 1109 Path moduleSrc = base.resolve("module-src"); 1110 Path m1 = moduleSrc.resolve("m1x"); 1111 Path m2 = moduleSrc.resolve("m2x"); 1112 1113 Path classes = base.resolve("classes"); 1114 Path cpClasses = base.resolve("cpClasses"); 1115 1116 Files.createDirectories(classes); 1117 Files.createDirectories(cpClasses); 1118 1119 tb.writeJavaFiles(m1, 1120 "module m1x { }", 1121 "package impl1; public class Impl { }", 1122 "package impl.conflict.module; class Impl { }", 1123 "package impl.conflict.clazz; public class pkg { public static class I { } }", 1124 "package impl.conflict.src; public class Impl { }", 1125 "package nested.pack.pack; public class Impl { }", 1126 "package unique.nested; public class Impl { }"); 1127 1128 tb.writeJavaFiles(m2, 1129 "module m2x { }", 1130 "package impl2; public class Impl { }", 1131 "package impl.conflict.module; class Impl { }", 1132 "package impl.conflict; public class clazz { public static class pkg { } }", 1133 "package nested.pack; public class Impl { }"); 1134 1135 //from source: 1136 String log = new JavacTask(tb) 1137 .options("--module-source-path", moduleSrc.toString(), 1138 "--source-path", src.toString(), 1139 "-processorpath", System.getProperty("test.class.path"), 1140 "-processor", UnboundLookup.class.getName(), 1141 "-XDrawDiagnostics") 1142 .outdir(classes) 1143 .files(findJavaFiles(moduleSrc)) 1144 .run() 1145 .writeAll() 1146 .getOutput(OutputKind.DIRECT); 1147 1148 String moduleImplConflictString = 1149 "- compiler.note.multiple.elements: getTypeElement, impl.conflict.module.Impl, m2x, m1x"; 1150 String srcConflictString = 1151 "- compiler.note.multiple.elements: getTypeElement, impl.conflict.src.Impl, m1x, unnamed module"; 1152 1153 if (!log.contains(moduleImplConflictString) || 1154 !log.contains(srcConflictString)) { 1155 throw new AssertionError("Expected output not found: " + log); 1156 } 1157 1158 if (log.split(Pattern.quote(moduleImplConflictString)).length > 2) { 1159 throw new AssertionError("Too many warnings in: " + log); 1160 } 1161 1162 new JavacTask(tb) 1163 .options("--source-path", src.toString()) 1164 .outdir(cpClasses) 1165 .files(findJavaFiles(src)) 1166 .run() 1167 .writeAll(); 1168 1169 //from classfiles: 1170 new JavacTask(tb) 1171 .options("--module-path", classes.toString(), 1172 "--class-path", cpClasses.toString(), 1173 "--add-modules", "m1x,m2x", 1174 "-processorpath", System.getProperty("test.class.path"), 1175 "-processor", UnboundLookup.class.getName(), 1176 "-proc:only") 1177 .classes("java.lang.Object") 1178 .run() 1179 .writeAll(); 1180 1181 //source 8: 1182 new JavacTask(tb) 1183 .options("--source-path", src.toString(), 1184 "-source", "8", 1185 "-processorpath", System.getProperty("test.class.path"), 1186 "-processor", UnboundLookup8.class.getName()) 1187 .outdir(cpClasses) 1188 .files(findJavaFiles(src)) 1189 .run() 1190 .writeAll(); 1191 1192 } 1193 1194 @SupportedAnnotationTypes("*") 1195 public static final class UnboundLookup extends AbstractProcessor { 1196 1197 @Override 1198 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 1199 assertTypeElementExists("impl1.Impl", "m1x"); 1200 assertPackageElementExists("impl1", "m1x"); 1201 assertTypeElementExists("impl2.Impl", "m2x"); 1202 assertTypeElementExists("impl.conflict.clazz.pkg.I", "m1x"); 1203 assertTypeElementExists("impl.conflict.clazz", "m2x"); 1204 assertPackageElementExists("impl.conflict.clazz", "m1x"); 1205 assertPackageElementExists("impl2", "m2x"); 1206 assertPackageElementExists("nested.pack.pack", "m1x"); 1207 assertPackageElementExists("nested.pack", "m2x"); 1208 assertTypeElementExists("unique.nested.Impl", "m1x"); 1209 assertTypeElementNotFound("impl.conflict.module.Impl"); 1210 assertTypeElementNotFound("impl.conflict.module.Impl"); //check that the warning/note is produced only once 1211 assertPackageElementNotFound("impl.conflict.module"); 1212 assertTypeElementNotFound("impl.conflict.src.Impl"); 1213 assertPackageElementNotFound("impl.conflict.src"); 1214 assertTypeElementNotFound("impl.conflict.clazz.pkg"); 1215 assertPackageElementNotFound("unique"); //do not return packages without members in module mode 1216 assertTypeElementNotFound("nested"); //cannot distinguish between m1x and m2x 1217 1218 return false; 1219 } 1220 1221 private void assertTypeElementExists(String name, String expectedModule) { 1222 assertElementExists(name, "class", processingEnv.getElementUtils() :: getTypeElement, expectedModule); 1223 } 1224 1225 private void assertPackageElementExists(String name, String expectedModule) { 1226 assertElementExists(name, "package", processingEnv.getElementUtils() :: getPackageElement, expectedModule); 1227 } 1228 1229 private void assertElementExists(String name, String type, Function<String, Element> getter, String expectedModule) { 1230 Element clazz = getter.apply(name); 1231 1232 if (clazz == null) { 1233 throw new AssertionError("No " + name + " " + type + " found."); 1234 } 1235 1236 ModuleElement mod = processingEnv.getElementUtils().getModuleOf(clazz); 1237 1238 if (!mod.getQualifiedName().contentEquals(expectedModule)) { 1239 throw new AssertionError(name + " found in an unexpected module: " + mod.getQualifiedName()); 1240 } 1241 } 1242 1243 private void assertTypeElementNotFound(String name) { 1244 assertElementNotFound(name, processingEnv.getElementUtils() :: getTypeElement); 1245 } 1246 1247 private void assertPackageElementNotFound(String name) { 1248 assertElementNotFound(name, processingEnv.getElementUtils() :: getPackageElement); 1249 } 1250 1251 private void assertElementNotFound(String name, Function<String, Element> getter) { 1252 Element found = getter.apply(name); 1253 1254 if (found != null) { 1255 fail("Element found unexpectedly: " + found); 1256 } 1257 } 1258 1259 @Override 1260 public SourceVersion getSupportedSourceVersion() { 1261 return SourceVersion.latest(); 1262 } 1263 1264 } 1265 1266 @SupportedAnnotationTypes("*") 1267 public static final class UnboundLookup8 extends AbstractProcessor { 1268 1269 @Override 1270 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 1271 if (processingEnv.getElementUtils().getTypeElement("impl.conflict.src.Impl") == null) { 1272 throw new AssertionError("impl.conflict.src.Impl."); 1273 } 1274 1275 if (processingEnv.getElementUtils().getModuleElement("java.base") != null) { 1276 throw new AssertionError("getModuleElement != null for -source 8"); 1277 } 1278 1279 return false; 1280 } 1281 1282 @Override 1283 public SourceVersion getSupportedSourceVersion() { 1284 return SourceVersion.latest(); 1285 } 1286 1287 } 1288 1289 private static void assertNonNull(String msg, Object val) { 1290 if (val == null) { 1291 throw new AssertionError(msg); 1292 } 1293 } 1294 1295 private static void assertNull(String msg, Object val) { 1296 if (val != null) { 1297 throw new AssertionError(msg); 1298 } 1299 } 1300 1301 private static void assertEquals(Object expected, Object actual) { 1302 if (!Objects.equals(expected, actual)) { 1303 throw new AssertionError("expected: " + expected + "; actual=" + actual); 1304 } 1305 } 1306 1307 private static void assertFileExists(Path base, String... pathElements) { 1308 Path file = resolveFile(base, pathElements); 1309 1310 if (!Files.exists(file)) { 1311 throw new AssertionError("Expected file: " + file + " exist, but it does not."); 1312 } 1313 } 1314 1315 static Path resolveFile(Path base, String... pathElements) { 1316 Path file = base; 1317 1318 for (String el : pathElements) { 1319 file = file.resolve(el); 1320 } 1321 1322 return file; 1323 } 1324 1325 private static void fail(String msg) { 1326 throw new AssertionError(msg); 1327 } 1328 1329} 1330