langtools/test/tools/javac/modules/AnnotationProcessing.java
changeset 44291 e1b620ac6c98
parent 43585 19e14d35add0
equal deleted inserted replaced
44290:202973b2d1ae 44291:e1b620ac6c98
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 
    23 
    24 /**
    24 /**
    25  * @test
    25  * @test
    26  * @bug 8133884 8162711 8133896 8172158 8172262 8173636
    26  * @bug 8133884 8162711 8133896 8172158 8172262 8173636 8175119
    27  * @summary Verify that annotation processing works.
    27  * @summary Verify that annotation processing works.
    28  * @library /tools/lib
    28  * @library /tools/lib
    29  * @modules
    29  * @modules
    30  *      jdk.compiler/com.sun.tools.javac.api
    30  *      jdk.compiler/com.sun.tools.javac.api
    31  *      jdk.compiler/com.sun.tools.javac.main
    31  *      jdk.compiler/com.sun.tools.javac.main
    35 
    35 
    36 import java.io.File;
    36 import java.io.File;
    37 import java.io.IOException;
    37 import java.io.IOException;
    38 import java.io.OutputStream;
    38 import java.io.OutputStream;
    39 import java.io.Reader;
    39 import java.io.Reader;
       
    40 import java.io.UncheckedIOException;
    40 import java.io.Writer;
    41 import java.io.Writer;
    41 import java.nio.file.Files;
    42 import java.nio.file.Files;
    42 import java.nio.file.Path;
    43 import java.nio.file.Path;
    43 import java.nio.file.Paths;
    44 import java.nio.file.Paths;
       
    45 import java.util.ArrayList;
    44 import java.util.Arrays;
    46 import java.util.Arrays;
    45 import java.util.HashMap;
    47 import java.util.HashMap;
    46 import java.util.HashSet;
    48 import java.util.HashSet;
    47 import java.util.List;
    49 import java.util.List;
    48 import java.util.Map;
    50 import java.util.Map;
    49 import java.util.Objects;
    51 import java.util.Objects;
    50 import java.util.Set;
    52 import java.util.Set;
    51 import java.util.concurrent.Callable;
    53 import java.util.concurrent.Callable;
       
    54 import java.util.function.Consumer;
    52 import java.util.function.Function;
    55 import java.util.function.Function;
    53 import java.util.regex.Pattern;
    56 import java.util.regex.Pattern;
    54 import java.util.stream.Collectors;
    57 import java.util.stream.Collectors;
    55 
    58 
    56 import javax.annotation.processing.AbstractProcessor;
    59 import javax.annotation.processing.AbstractProcessor;
   525 
   528 
   526         Path m1 = moduleSrc.resolve("m1x");
   529         Path m1 = moduleSrc.resolve("m1x");
   527 
   530 
   528         tb.writeJavaFiles(m1,
   531         tb.writeJavaFiles(m1,
   529                           "module m1x { exports api1; }",
   532                           "module m1x { exports api1; }",
   530                           "package api1; public class Api { GenApi ga; impl.Impl i; }");
   533                           "package api1; public class Api { }",
       
   534                           "package clash; public class C { }");
   531 
   535 
   532         writeFile("1", m1, "api1", "api");
   536         writeFile("1", m1, "api1", "api");
   533         writeFile("1", m1, "impl", "impl");
   537         writeFile("2", m1, "clash", "clash");
   534 
   538 
   535         Path m2 = moduleSrc.resolve("m2x");
   539         Path m2 = moduleSrc.resolve("m2x");
   536 
   540 
   537         tb.writeJavaFiles(m2,
   541         tb.writeJavaFiles(m2,
   538                           "module m2x { requires m1x; exports api2; }",
   542                           "module m2x { requires m1x; exports api2; }",
   539                           "package api2; public class Api { api1.GenApi ga1; GenApi qa2; impl.Impl i;}");
   543                           "package api2; public class Api { }",
   540 
   544                           "package clash; public class C { }");
   541         writeFile("2", m2, "api2", "api");
   545 
   542         writeFile("2", m2, "impl", "impl");
   546         writeFile("3", m2, "api2", "api");
   543 
   547         writeFile("4", m2, "clash", "api");
   544         for (FileType fileType : FileType.values()) {
   548 
   545             if (Files.isDirectory(classes)) {
   549         //passing testcases:
   546                 tb.cleanDirectory(classes);
   550         for (String module : Arrays.asList("", "m1x/")) {
   547             } else {
   551             for (String originating : Arrays.asList("", ", jlObject")) {
   548                 Files.createDirectories(classes);
   552                 tb.writeJavaFiles(m1,
   549             }
   553                                   "package test; class Test { api1.Impl i; }");
   550 
   554 
   551             new JavacTask(tb)
   555                 //source:
   552               .options("-processor", MultiModeAPITestAP.class.getName(),
   556                 runCompiler(base,
   553                        "--module-source-path", moduleSrc.toString(),
   557                             moduleSrc,
   554                        "-Afiletype=" + fileType.name())
   558                             classes,
   555               .outdir(classes)
   559                             "createSource(() -> filer.createSourceFile(\"" + module + "api1.Impl\"" + originating + "), \"api1.Impl\", \"package api1; public class Impl {}\")",
   556               .files(findJavaFiles(moduleSrc))
   560                             "--module-source-path", moduleSrc.toString());
   557               .run()
   561                 assertFileExists(classes, "m1x", "api1", "Impl.class");
   558               .writeAll();
   562 
   559 
   563                 //class:
   560             assertFileExists(classes, "m1x", "api1", "GenApi.class");
   564                 runCompiler(base,
   561             assertFileExists(classes, "m1x", "impl", "Impl.class");
   565                             moduleSrc,
   562             assertFileExists(classes, "m1x", "api1", "gen1");
   566                             classes,
   563             assertFileExists(classes, "m2x", "api2", "GenApi.class");
   567                             "createClass(() -> filer.createClassFile(\"" + module + "api1.Impl\"" + originating + "), \"api1.Impl\", \"package api1; public class Impl {}\")",
   564             assertFileExists(classes, "m2x", "impl", "Impl.class");
   568                             "--module-source-path", moduleSrc.toString());
   565             assertFileExists(classes, "m2x", "api2", "gen1");
   569                 assertFileExists(classes, "m1x", "api1", "Impl.class");
   566         }
   570 
   567     }
   571                 Files.delete(m1.resolve("test").resolve("Test.java"));
   568 
   572 
   569     enum FileType {
   573                 //resource class output:
   570         SOURCE,
   574                 runCompiler(base,
   571         CLASS;
   575                             moduleSrc,
       
   576                             classes,
       
   577                             "createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"" + module + "api1\", \"impl\"" + originating + "), \"impl\", \"impl\")",
       
   578                             "--module-source-path", moduleSrc.toString());
       
   579                 assertFileExists(classes, "m1x", "api1", "impl");
       
   580             }
       
   581         }
       
   582 
       
   583         //get resource module source path:
       
   584         runCompiler(base,
       
   585                     m1,
       
   586                     classes,
       
   587                     "doReadResource(() -> filer.getResource(StandardLocation.MODULE_SOURCE_PATH, \"m1x/api1\", \"api\"), \"1\")",
       
   588                     "--module-source-path", moduleSrc.toString());
       
   589 
       
   590         //can generate resources to the single root module:
       
   591         runCompiler(base,
       
   592                     m1,
       
   593                     classes,
       
   594                     "createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"m1x/impl\", \"impl\"), \"impl\", \"impl\")",
       
   595                     "--module-source-path", moduleSrc.toString());
       
   596         assertFileExists(classes, "m1x", "impl", "impl");
       
   597 
       
   598         //check --default-module-for-created-files option:
       
   599         for (String pack : Arrays.asList("clash", "doesnotexist")) {
       
   600             tb.writeJavaFiles(m1,
       
   601                               "package test; class Test { " + pack + ".Pass i; }");
       
   602             runCompiler(base,
       
   603                         moduleSrc,
       
   604                         classes,
       
   605                         "createSource(() -> filer.createSourceFile(\"" + pack + ".Pass\")," +
       
   606                         "                                          \"" + pack + ".Pass\"," +
       
   607                         "                                          \"package " + pack + ";" +
       
   608                         "                                            public class Pass { }\")",
       
   609                         "--module-source-path", moduleSrc.toString(),
       
   610                         "--default-module-for-created-files=m1x");
       
   611             assertFileExists(classes, "m1x", pack, "Pass.class");
       
   612             assertFileNotExists(classes, "m2x", pack, "Pass.class");
       
   613 
       
   614             runCompiler(base,
       
   615                         moduleSrc,
       
   616                         classes,
       
   617                         "createClass(() -> filer.createClassFile(\"" + pack + ".Pass\")," +
       
   618                         "                                        \"" + pack + ".Pass\"," +
       
   619                         "                                        \"package " + pack + ";" +
       
   620                         "                                          public class Pass { }\")",
       
   621                         "--module-source-path", moduleSrc.toString(),
       
   622                         "--default-module-for-created-files=m1x");
       
   623             assertFileExists(classes, "m1x", pack, "Pass.class");
       
   624             assertFileNotExists(classes, "m2x", pack, "Pass.class");
       
   625 
       
   626             Files.delete(m1.resolve("test").resolve("Test.java"));
       
   627 
       
   628             runCompiler(base,
       
   629                         moduleSrc,
       
   630                         classes,
       
   631                         "createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT," +
       
   632                         "                                        \"" + pack + "\", \"impl\"), \"impl\", \"impl\")",
       
   633                         "--module-source-path", moduleSrc.toString(),
       
   634                         "--default-module-for-created-files=m1x");
       
   635             assertFileExists(classes, "m1x", pack, "impl");
       
   636             assertFileNotExists(classes, "m2x", pack, "impl");
       
   637 
       
   638             runCompiler(base,
       
   639                         moduleSrc,
       
   640                         classes,
       
   641                         "doReadResource(() -> filer.getResource(StandardLocation.CLASS_OUTPUT," +
       
   642                         "                                       \"" + pack + "\", \"resource\"), \"1\")",
       
   643                         p -> writeFile("1", p.resolve("m1x"), pack, "resource"),
       
   644                         "--module-source-path", moduleSrc.toString(),
       
   645                         "--default-module-for-created-files=m1x");
       
   646         }
       
   647 
       
   648         //wrong default module:
       
   649         runCompiler(base,
       
   650                     moduleSrc,
       
   651                     classes,
       
   652                     "expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT," +
       
   653                     "                                                \"clash\", \"impl\"))",
       
   654                     "--module-source-path", moduleSrc.toString(),
       
   655                     "--default-module-for-created-files=doesnotexist");
       
   656 
       
   657         String[] failingCases = {
       
   658             //must not generate to unnamed package:
       
   659             "expectFilerException(() -> filer.createSourceFile(\"Fail\"))",
       
   660             "expectFilerException(() -> filer.createClassFile(\"Fail\"))",
       
   661             "expectFilerException(() -> filer.createSourceFile(\"m1x/Fail\"))",
       
   662             "expectFilerException(() -> filer.createClassFile(\"m1x/Fail\"))",
       
   663 
       
   664             //cannot infer module name, package clash:
       
   665             "expectFilerException(() -> filer.createSourceFile(\"clash.Fail\"))",
       
   666             "expectFilerException(() -> filer.createClassFile(\"clash.Fail\"))",
       
   667             "expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"clash\", \"impl\"))",
       
   668             "expectFilerException(() -> filer.getResource(StandardLocation.CLASS_OUTPUT, \"clash\", \"impl\"))",
       
   669 
       
   670             //cannot infer module name, package does not exist:
       
   671             "expectFilerException(() -> filer.createSourceFile(\"doesnotexist.Fail\"))",
       
   672             "expectFilerException(() -> filer.createClassFile(\"doesnotexist.Fail\"))",
       
   673             "expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"doesnotexist\", \"impl\"))",
       
   674             "expectFilerException(() -> filer.getResource(StandardLocation.CLASS_OUTPUT, \"doesnotexist\", \"impl\"))",
       
   675 
       
   676             //cannot generate sources/classes to modules that are not root modules:
       
   677             "expectFilerException(() -> filer.createSourceFile(\"java.base/fail.Fail\"))",
       
   678             "expectFilerException(() -> filer.createClassFile(\"java.base/fail.Fail\"))",
       
   679 
       
   680             //cannot read from module locations if module not given and not inferable:
       
   681             "expectFilerException(() -> filer.getResource(StandardLocation.SYSTEM_MODULES, \"fail\", \"Fail\"))",
       
   682 
       
   683             //wrong module given:
       
   684             "expectException(() -> filer.getResource(StandardLocation.SYSTEM_MODULES, \"java.compiler/java.lang\", \"Object.class\"))",
       
   685         };
       
   686 
       
   687         for (String failingCode : failingCases) {
       
   688             System.err.println("failing code: " + failingCode);
       
   689             runCompiler(base,
       
   690                         moduleSrc,
       
   691                         classes,
       
   692                         failingCode,
       
   693                         "--module-source-path", moduleSrc.toString());
       
   694         }
   572     }
   695     }
   573 
   696 
   574     public static abstract class GeneratingAP extends AbstractProcessor {
   697     public static abstract class GeneratingAP extends AbstractProcessor {
   575 
   698 
   576         void createSource(CreateFileObject file, String name, String content) {
   699         public void createSource(CreateFileObject file, String name, String content) {
   577             try (Writer out = file.create().openWriter()) {
   700             try (Writer out = file.create().openWriter()) {
   578                 out.write(content);
   701                 out.write(content);
   579             } catch (IOException ex) {
   702             } catch (IOException ex) {
   580                 throw new IllegalStateException(ex);
   703                 throw new IllegalStateException(ex);
   581             }
   704             }
   582         }
   705         }
   583 
   706 
   584         void createClass(CreateFileObject file, String name, String content) {
   707         public void createClass(CreateFileObject file, String name, String content) {
   585             String fileNameStub = name.replace(".", File.separator);
   708             String fileNameStub = name.replace(".", File.separator);
   586 
   709 
   587             try (OutputStream out = file.create().openOutputStream()) {
   710             try (OutputStream out = file.create().openOutputStream()) {
   588                 Path scratch = Files.createDirectories(Paths.get(""));
   711                 Path scratch = Files.createDirectories(Paths.get(""));
   589                 Path scratchSrc = scratch.resolve(fileNameStub + ".java").toAbsolutePath();
   712                 Path scratchSrc = scratch.resolve(fileNameStub + ".java").toAbsolutePath();
   615             } catch (IOException ex) {
   738             } catch (IOException ex) {
   616                 throw new IllegalStateException(ex);
   739                 throw new IllegalStateException(ex);
   617             }
   740             }
   618         }
   741         }
   619 
   742 
   620         void doReadResource(CreateFileObject file, String expectedContent) {
   743         public void doReadResource(CreateFileObject file, String expectedContent) {
   621             try {
   744             try {
   622                 StringBuilder actualContent = new StringBuilder();
   745                 StringBuilder actualContent = new StringBuilder();
   623 
   746 
   624                 try (Reader r = file.create().openReader(true)) {
   747                 try (Reader r = file.create().openReader(true)) {
   625                     int read;
   748                     int read;
   634             } catch (IOException ex) {
   757             } catch (IOException ex) {
   635                 throw new IllegalStateException(ex);
   758                 throw new IllegalStateException(ex);
   636             }
   759             }
   637         }
   760         }
   638 
   761 
       
   762         public void checkResourceExists(CreateFileObject file) {
       
   763             try {
       
   764                 file.create().openInputStream().close();
       
   765             } catch (IOException ex) {
       
   766                 throw new IllegalStateException(ex);
       
   767             }
       
   768         }
       
   769 
   639         public interface CreateFileObject {
   770         public interface CreateFileObject {
   640             public FileObject create() throws IOException;
   771             public FileObject create() throws IOException;
   641         }
   772         }
   642 
   773 
   643         void expectFilerException(Callable<Object> c) {
   774         public void expectFilerException(Callable<Object> c) {
   644             try {
   775             try {
   645                 c.call();
   776                 c.call();
   646                 throw new AssertionError("Expected exception not thrown");
   777                 throw new AssertionError("Expected exception not thrown");
   647             } catch (FilerException ex) {
   778             } catch (FilerException ex) {
   648                 //expected
   779                 //expected
   649             } catch (Exception ex) {
   780             } catch (Exception ex) {
   650                 throw new IllegalStateException(ex);
   781                 throw new IllegalStateException(ex);
   651             }
   782             }
   652         }
   783         }
   653 
   784 
       
   785         public void expectException(Callable<Object> c) {
       
   786             try {
       
   787                 c.call();
       
   788                 throw new AssertionError("Expected exception not thrown");
       
   789             } catch (IOException ex) {
       
   790                 //expected
       
   791             } catch (Exception ex) {
       
   792                 throw new IllegalStateException(ex);
       
   793             }
       
   794         }
       
   795 
   654         @Override
   796         @Override
   655         public SourceVersion getSupportedSourceVersion() {
   797         public SourceVersion getSupportedSourceVersion() {
   656             return SourceVersion.latest();
   798             return SourceVersion.latest();
   657         }
   799         }
   658 
   800 
   659     }
   801     }
   660 
   802 
   661     @SupportedAnnotationTypes("*")
   803     @Test
   662     @SupportedOptions({"filetype", "modulename"})
   804     public void testGenerateSingleModule(Path base) throws Exception {
   663     public static final class MultiModeAPITestAP extends GeneratingAP {
   805         Path classes = base.resolve("classes");
   664 
   806 
   665         int round;
   807         Files.createDirectories(classes);
   666 
   808 
   667         @Override
   809         Path src = base.resolve("module-src");
   668         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   810         Path m1 = src.resolve("m1x");
   669             if (round++ != 0)
   811 
   670                 return false;
   812         tb.writeJavaFiles(m1,
   671 
   813                           "module m1x { }",
   672             createClass("m1x", "api1.GenApi", "package api1; public class GenApi {}");
   814                           "package test; class Test { impl.Impl i; }");
   673             createClass("m1x", "impl.Impl", "package impl; public class Impl {}");
   815         Path m2 = src.resolve("m2x");
   674             createClass("m2x", "api2.GenApi", "package api2; public class GenApi {}");
   816 
   675             createClass("m2x", "impl.Impl", "package impl; public class Impl {}");
   817         tb.writeJavaFiles(m2,
   676 
   818                           "module m2x { }");
   677             createResource("m1x", "api1", "gen1");
   819 
   678             createResource("m2x", "api2", "gen1");
   820         for (String[] options : new String[][] {new String[] {"-sourcepath", m1.toString()},
   679 
   821                                                 new String[] {"--module-source-path", src.toString()}}) {
   680             readResource("m1x", "api1", "api", "1");
   822             String modulePath = options[0].equals("--module-source-path") ? "m1x" : "";
   681             readResource("m1x", "impl", "impl", "1");
   823             //passing testcases:
   682             readResource("m2x", "api2", "api", "2");
   824             for (String module : Arrays.asList("", "m1x/")) {
   683             readResource("m2x", "impl", "impl", "2");
   825                 for (String originating : Arrays.asList("", ", jlObject")) {
   684 
   826                     tb.writeJavaFiles(m1,
   685             Filer filer = processingEnv.getFiler();
   827                                       "package test; class Test { impl.Impl i; }");
   686 
   828 
   687             expectFilerException(() -> filer.createSourceFile("fail.Fail"));
   829                     //source:
   688             expectFilerException(() -> filer.createClassFile("fail.Fail"));
   830                     runCompiler(base,
   689             expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "fail", "fail"));
   831                                 m1,
   690             expectFilerException(() -> filer.getResource(StandardLocation.MODULE_SOURCE_PATH, "fail", "fail"));
   832                                 classes,
   691 
   833                                 "createSource(() -> filer.createSourceFile(\"" + module + "impl.Impl\"" + originating + "), \"impl.Impl\", \"package impl; public class Impl {}\")",
       
   834                                 options);
       
   835                     assertFileExists(classes, modulePath, "impl", "Impl.class");
       
   836 
       
   837                     //class:
       
   838                     runCompiler(base,
       
   839                                 m1,
       
   840                                 classes,
       
   841                                 "createClass(() -> filer.createClassFile(\"" + module + "impl.Impl\"" + originating + "), \"impl.Impl\", \"package impl; public class Impl {}\")",
       
   842                                 options);
       
   843                     assertFileExists(classes, modulePath, "impl", "Impl.class");
       
   844 
       
   845                     Files.delete(m1.resolve("test").resolve("Test.java"));
       
   846 
       
   847                     //resource class output:
       
   848                     runCompiler(base,
       
   849                                 m1,
       
   850                                 classes,
       
   851                                 "createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"impl\", \"impl\"" + originating + "), \"impl\", \"impl\")",
       
   852                                 options);
       
   853                     assertFileExists(classes, modulePath, "impl", "impl");
       
   854                 }
       
   855             }
       
   856         }
       
   857 
       
   858         //get resource source path:
       
   859         writeFile("1", m1, "impl", "resource");
       
   860         runCompiler(base,
       
   861                     m1,
       
   862                     classes,
       
   863                     "doReadResource(() -> filer.getResource(StandardLocation.SOURCE_PATH, \"impl\", \"resource\"), \"1\")",
       
   864                     "-sourcepath", m1.toString());
       
   865         //must not specify module when reading non-module oriented locations:
       
   866         runCompiler(base,
       
   867                     m1,
       
   868                     classes,
       
   869                     "expectFilerException(() -> filer.getResource(StandardLocation.SOURCE_PATH, \"m1x/impl\", \"resource\"))",
       
   870                     "-sourcepath", m1.toString());
       
   871 
       
   872         Files.delete(m1.resolve("impl").resolve("resource"));
       
   873 
       
   874         //can read resources from the system module path if module name given:
       
   875         runCompiler(base,
       
   876                     m1,
       
   877                     classes,
       
   878                     "checkResourceExists(() -> filer.getResource(StandardLocation.SYSTEM_MODULES, \"java.base/java.lang\", \"Object.class\"))",
       
   879                     "-sourcepath", m1.toString());
       
   880 
       
   881         //can read resources from the system module path if module inferable:
       
   882         runCompiler(base,
       
   883                     m1,
       
   884                     classes,
       
   885                     "expectFilerException(() -> filer.getResource(StandardLocation.SYSTEM_MODULES, \"java.lang\", \"Object.class\"))",
       
   886                     "-sourcepath", m1.toString());
       
   887 
       
   888         //cannot generate resources to modules that are not root modules:
       
   889         runCompiler(base,
       
   890                     m1,
       
   891                     classes,
       
   892                     "expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"java.base/fail\", \"Fail\"))",
       
   893                     "--module-source-path", src.toString());
       
   894 
       
   895         //can generate resources to the single root module:
       
   896         runCompiler(base,
       
   897                     m1,
       
   898                     classes,
       
   899                     "createSource(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"impl\", \"impl\"), \"impl\", \"impl\")",
       
   900                     "--module-source-path", src.toString());
       
   901         assertFileExists(classes, "m1x", "impl", "impl");
       
   902 
       
   903         String[] failingCases = {
   692             //must not generate to unnamed package:
   904             //must not generate to unnamed package:
   693             expectFilerException(() -> filer.createSourceFile("m1/Fail"));
   905             "expectFilerException(() -> filer.createSourceFile(\"Fail\"))",
   694             expectFilerException(() -> filer.createClassFile("m1/Fail"));
   906             "expectFilerException(() -> filer.createClassFile(\"Fail\"))",
   695 
   907             "expectFilerException(() -> filer.createSourceFile(\"m1x/Fail\"))",
   696             //cannot generate resources to modules that are not root modules:
   908             "expectFilerException(() -> filer.createClassFile(\"m1x/Fail\"))",
   697             expectFilerException(() -> filer.createSourceFile("java.base/fail.Fail"));
   909 
   698             expectFilerException(() -> filer.createClassFile("java.base/fail.Fail"));
   910             //cannot generate sources/classes to modules that are not root modules:
   699             expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, "java.base/fail", "Fail"));
   911             "expectFilerException(() -> filer.createSourceFile(\"java.base/fail.Fail\"))",
   700 
   912             "expectFilerException(() -> filer.createClassFile(\"java.base/fail.Fail\"))",
   701             return false;
   913 
   702         }
   914             //cannot specify module name for class output when not in the multi-module mode:
   703 
   915             "expectFilerException(() -> filer.createResource(StandardLocation.CLASS_OUTPUT, \"m1x/fail\", \"Fail\"))",
   704         void createClass(String expectedModule, String name, String content) {
   916 
   705             Filer filer = processingEnv.getFiler();
   917             //cannot read from module locations if module not given:
   706             FileType filetype = FileType.valueOf(processingEnv.getOptions().getOrDefault("filetype", ""));
   918             "expectFilerException(() -> filer.getResource(StandardLocation.SYSTEM_MODULES, \"fail\", \"Fail\"))",
   707 
   919 
   708             switch (filetype) {
   920             //wrong module given:
   709                 case SOURCE:
   921             "expectException(() -> filer.getResource(StandardLocation.SYSTEM_MODULES, \"java.compiler/java.lang\", \"Object.class\"))",
   710                     createSource(() -> filer.createSourceFile(expectedModule + "/" + name), name, content);
   922         };
   711                     break;
   923 
   712                 case CLASS:
   924         for (String failingCode : failingCases) {
   713                     createClass(() -> filer.createClassFile(expectedModule + "/" + name), name, content);
   925             System.err.println("failing code: " + failingCode);
   714                     break;
   926             runCompiler(base,
   715                 default:
   927                         m1,
   716                     throw new AssertionError("Unexpected filetype: " + filetype);
   928                         classes,
   717             }
   929                         failingCode,
   718         }
   930                         "-sourcepath", m1.toString());
   719 
   931         }
   720         void createResource(String expectedModule, String pkg, String relName) {
   932 
   721             try {
   933         Files.delete(m1.resolve("module-info.java"));
   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,
   934         tb.writeJavaFiles(m1,
   750                           "module m1x { }");
   935                           "package test; class Test { }");
   751 
   936 
   752         writeFile("3", m1, "impl", "resource");
   937         runCompiler(base,
   753 
   938                     m1,
       
   939                     classes,
       
   940                     "expectFilerException(() -> filer.createSourceFile(\"m1x/impl.Impl\"))",
       
   941                     "-sourcepath", m1.toString(),
       
   942                     "-source", "8");
       
   943 
       
   944         runCompiler(base,
       
   945                     m1,
       
   946                     classes,
       
   947                     "expectFilerException(() -> filer.createClassFile(\"m1x/impl.Impl\"))",
       
   948                     "-sourcepath", m1.toString(),
       
   949                     "-source", "8");
       
   950     }
       
   951 
       
   952     private void runCompiler(Path base, Path src, Path classes,
       
   953                              String code, String... options) throws IOException {
       
   954         runCompiler(base, src, classes, code, p -> {}, options);
       
   955     }
       
   956 
       
   957     private void runCompiler(Path base, Path src, Path classes,
       
   958                              String code, Consumer<Path> generateToClasses,
       
   959                              String... options) throws IOException {
       
   960         Path apClasses = base.resolve("ap-classes");
       
   961         if (Files.exists(apClasses)) {
       
   962             tb.cleanDirectory(apClasses);
       
   963         } else {
       
   964             Files.createDirectories(apClasses);
       
   965         }
       
   966         compileAP(apClasses, code);
       
   967         if (Files.exists(classes)) {
       
   968             tb.cleanDirectory(classes);
       
   969         } else {
       
   970             Files.createDirectories(classes);
       
   971         }
       
   972         generateToClasses.accept(classes);
       
   973         List<String> opts = new ArrayList<>();
       
   974         opts.addAll(Arrays.asList(options));
       
   975         opts.add("-processorpath");
       
   976         opts.add(System.getProperty("test.class.path") + File.pathSeparator + apClasses.toString());
       
   977         opts.add("-processor");
       
   978         opts.add("AP");
   754         new JavacTask(tb)
   979         new JavacTask(tb)
   755           .options("-processor", SingleNameModeAPITestAP.class.getName(),
   980           .options(opts)
   756                    "-sourcepath", m1.toString())
       
   757           .outdir(classes)
   981           .outdir(classes)
   758           .files(findJavaFiles(m1))
   982           .files(findJavaFiles(src))
   759           .run()
   983           .run()
   760           .writeAll();
   984           .writeAll();
   761 
   985     }
   762         assertFileExists(classes, "impl", "Impl1.class");
   986 
   763         assertFileExists(classes, "impl", "Impl2.class");
   987     private void compileAP(Path target, String code) {
   764         assertFileExists(classes, "impl", "Impl3");
   988         String processorCode =
   765         assertFileExists(classes, "impl", "Impl4.class");
   989             "import java.util.*;\n" +
   766         assertFileExists(classes, "impl", "Impl5.class");
   990             "import javax.annotation.processing.*;\n" +
   767         assertFileExists(classes, "impl", "Impl6");
   991             "import javax.lang.model.*;\n" +
   768         assertFileExists(classes, "impl", "Impl7.class");
   992             "import javax.lang.model.element.*;\n" +
   769         assertFileExists(classes, "impl", "Impl8.class");
   993             "import javax.lang.model.type.*;\n" +
   770         assertFileExists(classes, "impl", "Impl9");
   994             "import javax.lang.model.util.*;\n" +
   771     }
   995             "import javax.tools.*;\n" +
   772 
   996             "@SupportedAnnotationTypes(\"*\")\n" +
   773 
   997             "public final class AP extends AnnotationProcessing.GeneratingAP {\n" +
   774     @SupportedAnnotationTypes("*")
   998             "\n" +
   775     public static final class SingleNameModeAPITestAP extends GeneratingAP {
   999             "        int round;\n" +
   776 
  1000             "\n" +
   777         int round;
  1001             "        @Override\n" +
   778 
  1002             "        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n" +
   779         @Override
  1003             "            if (round++ != 0)\n" +
   780         public synchronized void init(ProcessingEnvironment processingEnv) {
  1004             "                return false;\n" +
   781             super.init(processingEnv);
  1005             "            Filer filer = processingEnv.getFiler();\n" +
   782         }
  1006             "            TypeElement jlObject = processingEnv.getElementUtils().getTypeElement(\"java.lang.Object\");\n" +
   783 
  1007             code + ";\n" +
   784         @Override
  1008             "            return false;\n" +
   785         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  1009             "        }\n" +
   786             if (round++ != 0)
  1010             "    }\n";
   787                 return false;
  1011         new JavacTask(tb)
   788 
  1012           .options("-classpath", System.getProperty("test.class.path"))
   789             Filer filer = processingEnv.getFiler();
  1013           .sources(processorCode)
   790 
  1014           .outdir(target)
   791             createSource(() -> filer.createSourceFile("impl.Impl1"), "impl.Impl1", "package impl; class Impl1 {}");
  1015           .run()
   792             createClass(() -> filer.createClassFile("impl.Impl2"), "impl.Impl2", "package impl; class Impl2 {}");
  1016           .writeAll();
   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     }
  1017     }
   823 
  1018 
   824     @Test
  1019     @Test
   825     public void testGenerateInUnnamedModeAPI(Path base) throws Exception {
  1020     public void testGenerateInUnnamedModeAPI(Path base) throws Exception {
   826         Path classes = base.resolve("classes");
  1021         Path classes = base.resolve("classes");
  1087             return Set.of("m2x/api.A");
  1282             return Set.of("m2x/api.A");
  1088         }
  1283         }
  1089 
  1284 
  1090     }
  1285     }
  1091 
  1286 
  1092     private static void writeFile(String content, Path base, String... pathElements) throws IOException {
  1287     private static void writeFile(String content, Path base, String... pathElements) {
  1093         Path file = resolveFile(base, pathElements);
  1288         try {
  1094 
  1289             Path file = resolveFile(base, pathElements);
  1095         Files.createDirectories(file.getParent());
  1290 
  1096 
  1291             Files.createDirectories(file.getParent());
  1097         try (Writer out = Files.newBufferedWriter(file)) {
  1292 
  1098             out.append(content);
  1293             try (Writer out = Files.newBufferedWriter(file)) {
       
  1294                 out.append(content);
       
  1295             }
       
  1296         } catch (IOException ex) {
       
  1297             throw new UncheckedIOException(ex);
  1099         }
  1298         }
  1100     }
  1299     }
  1101 
  1300 
  1102     @Test
  1301     @Test
  1103     public void testUnboundLookup(Path base) throws Exception {
  1302     public void testUnboundLookup(Path base) throws Exception {
  1284             return SourceVersion.latest();
  1483             return SourceVersion.latest();
  1285         }
  1484         }
  1286 
  1485 
  1287     }
  1486     }
  1288 
  1487 
       
  1488     @Test
       
  1489     public void testWrongDefaultTargetModule(Path base) throws Exception {
       
  1490         Path src = base.resolve("src");
       
  1491 
       
  1492         tb.writeJavaFiles(src,
       
  1493                           "package test; public class Test { }");
       
  1494 
       
  1495         Path classes = base.resolve("classes");
       
  1496 
       
  1497         Files.createDirectories(classes);
       
  1498 
       
  1499         List<String> log = new JavacTask(tb)
       
  1500             .options("--default-module-for-created-files=m!",
       
  1501                      "-XDrawDiagnostics")
       
  1502             .outdir(classes)
       
  1503             .files(findJavaFiles(src))
       
  1504             .run(Task.Expect.FAIL)
       
  1505             .writeAll()
       
  1506             .getOutputLines(OutputKind.DIRECT);
       
  1507 
       
  1508         List<String> expected = Arrays.asList(
       
  1509             "- compiler.err.bad.name.for.option: --default-module-for-created-files, m!"
       
  1510         );
       
  1511 
       
  1512         if (!log.equals(expected)) {
       
  1513             throw new AssertionError("Expected output not found.");
       
  1514         }
       
  1515     }
       
  1516 
  1289     private static void assertNonNull(String msg, Object val) {
  1517     private static void assertNonNull(String msg, Object val) {
  1290         if (val == null) {
  1518         if (val == null) {
  1291             throw new AssertionError(msg);
  1519             throw new AssertionError(msg);
  1292         }
  1520         }
  1293     }
  1521     }
  1310         if (!Files.exists(file)) {
  1538         if (!Files.exists(file)) {
  1311             throw new AssertionError("Expected file: " + file + " exist, but it does not.");
  1539             throw new AssertionError("Expected file: " + file + " exist, but it does not.");
  1312         }
  1540         }
  1313     }
  1541     }
  1314 
  1542 
       
  1543     private static void assertFileNotExists(Path base, String... pathElements) {
       
  1544         Path file = resolveFile(base, pathElements);
       
  1545 
       
  1546         if (Files.exists(file)) {
       
  1547             throw new AssertionError("Expected file: " + file + " exist, but it does not.");
       
  1548         }
       
  1549     }
       
  1550 
  1315     static Path resolveFile(Path base, String... pathElements) {
  1551     static Path resolveFile(Path base, String... pathElements) {
  1316         Path file = base;
  1552         Path file = base;
  1317 
  1553 
  1318         for (String el : pathElements) {
  1554         for (String el : pathElements) {
  1319             file = file.resolve(el);
  1555             file = file.resolve(el);