1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @summary Verify that annotation processors inside modules works
  27  * @library /tools/lib
  28  * @modules jdk.compiler/com.sun.tools.javac.api
  29  *          jdk.compiler/com.sun.tools.javac.main
  30  * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
  31  * @run main AnnotationProcessorsInModulesTest
  32  */
  33 
  34 import java.nio.file.Files;
  35 import java.nio.file.Path;
  36 import java.util.Arrays;
  37 import java.util.List;
  38 
  39 import toolbox.JavacTask;
  40 import toolbox.Task;
  41 import toolbox.ToolBox;
  42 
  43 public class AnnotationProcessorsInModulesTest extends ModuleTestBase {
  44 
  45     public static void main(String... args) throws Exception {
  46         new AnnotationProcessorsInModulesTest().runTests();
  47     }
  48 
  49     private static final String annotationProcessorModule1 =
  50             "module anno_proc1 {\n" +
  51             "    requires java.compiler;\n" +
  52             "\n" +
  53             "    provides javax.annotation.processing.Processor\n" +
  54             "      with mypkg1.MyProcessor1;\n" +
  55             "}";
  56 
  57     private static final String annotationProcessorModule2 =
  58             "module anno_proc2 {\n" +
  59             "    requires java.compiler;\n" +
  60             "\n" +
  61             "    provides javax.annotation.processing.Processor\n" +
  62             "      with mypkg2.MyProcessor2;\n" +
  63             "}";
  64 
  65     private static final String annotationProcessor1 =
  66             "package mypkg1;\n" +
  67             "\n" +
  68             "import javax.annotation.processing.AbstractProcessor;\n" +
  69             "import javax.annotation.processing.RoundEnvironment;\n" +
  70             "import javax.annotation.processing.SupportedAnnotationTypes;\n" +
  71             "import javax.lang.model.SourceVersion;\n" +
  72             "import javax.lang.model.element.*;\n" +
  73             "\n" +
  74             "import java.util.*;\n" +
  75             "\n" +
  76             "@SupportedAnnotationTypes(\"*\")\n" +
  77             "public final class MyProcessor1 extends AbstractProcessor {\n" +
  78             "\n" +
  79             "    @Override\n" +
  80             "    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n" +
  81             "        return false;\n" +
  82             "    }\n" +
  83             "\n" +
  84             "    @Override\n" +
  85             "    public SourceVersion getSupportedSourceVersion() {\n" +
  86             "        System.out.println(\"the annotation processor 1 is working!\");\n" +
  87             "        return SourceVersion.latest();\n" +
  88             "    }\n" +
  89             "}";
  90 
  91     private static final String annotationProcessor2 =
  92             "package mypkg2;\n" +
  93             "\n" +
  94             "import javax.annotation.processing.AbstractProcessor;\n" +
  95             "import javax.annotation.processing.RoundEnvironment;\n" +
  96             "import javax.annotation.processing.SupportedAnnotationTypes;\n" +
  97             "import javax.lang.model.SourceVersion;\n" +
  98             "import javax.lang.model.element.*;\n" +
  99             "\n" +
 100             "import java.util.*;\n" +
 101             "\n" +
 102             "@SupportedAnnotationTypes(\"*\")\n" +
 103             "public final class MyProcessor2 extends AbstractProcessor {\n" +
 104             "\n" +
 105             "    @Override\n" +
 106             "    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n" +
 107             "        return false;\n" +
 108             "    }\n" +
 109             "\n" +
 110             "    @Override\n" +
 111             "    public SourceVersion getSupportedSourceVersion() {\n" +
 112             "        System.out.println(\"the annotation processor 2 is working!\");\n" +
 113             "        return SourceVersion.latest();\n" +
 114             "    }\n" +
 115             "}";
 116 
 117     private static final String testClass = "class Test{}";
 118 
 119     void initialization(Path base) throws Exception {
 120         moduleSrc = base.resolve("anno_proc_src");
 121         Path anno_proc1 = moduleSrc.resolve("anno_proc1");
 122         Path anno_proc2 = moduleSrc.resolve("anno_proc2");
 123 
 124         processorCompiledModules = base.resolve("mods");
 125 
 126         Files.createDirectories(processorCompiledModules);
 127 
 128         tb.writeJavaFiles(
 129                 anno_proc1,
 130                 annotationProcessorModule1,
 131                 annotationProcessor1);
 132 
 133         tb.writeJavaFiles(
 134                 anno_proc2,
 135                 annotationProcessorModule2,
 136                 annotationProcessor2);
 137 
 138         String log = new JavacTask(tb)
 139                 .options("--module-source-path", moduleSrc.toString())
 140                 .outdir(processorCompiledModules)
 141                 .files(findJavaFiles(moduleSrc))
 142                 .run()
 143                 .writeAll()
 144                 .getOutput(Task.OutputKind.DIRECT);
 145 
 146         if (!log.isEmpty()) {
 147             throw new AssertionError("Unexpected output: " + log);
 148         }
 149 
 150         classes = base.resolve("classes");
 151         Files.createDirectories(classes);
 152     }
 153 
 154     Path processorCompiledModules;
 155     Path moduleSrc;
 156     Path classes;
 157 
 158     @Test
 159     public void testUseOnlyOneProcessor(Path base) throws Exception {
 160         initialization(base);
 161         String log = new JavacTask(tb)
 162                 .options("--processor-module-path", processorCompiledModules.toString(),
 163                         "-processor", "mypkg2.MyProcessor2")
 164                 .outdir(classes)
 165                 .sources(testClass)
 166                 .run()
 167                 .writeAll()
 168                 .getOutput(Task.OutputKind.STDOUT);
 169         if (!log.trim().equals("the annotation processor 2 is working!")) {
 170             throw new AssertionError("Unexpected output: " + log);
 171         }
 172     }
 173 
 174     @Test
 175     public void testAnnotationProcessorExecutionOrder(Path base) throws Exception {
 176         initialization(base);
 177         List<String> log = new JavacTask(tb)
 178                 .options("--processor-module-path", processorCompiledModules.toString(),
 179                         "-processor", "mypkg1.MyProcessor1,mypkg2.MyProcessor2")
 180                 .outdir(classes)
 181                 .sources(testClass)
 182                 .run()
 183                 .writeAll()
 184                 .getOutputLines(Task.OutputKind.STDOUT);
 185         if (!log.equals(Arrays.asList("the annotation processor 1 is working!",
 186                                       "the annotation processor 2 is working!"))) {
 187             throw new AssertionError("Unexpected output: " + log);
 188         }
 189 
 190         log = new JavacTask(tb)
 191                 .options("--processor-module-path", processorCompiledModules.toString(),
 192                         "-processor", "mypkg2.MyProcessor2,mypkg1.MyProcessor1")
 193                 .outdir(classes)
 194                 .sources(testClass)
 195                 .run()
 196                 .writeAll()
 197                 .getOutputLines(Task.OutputKind.STDOUT);
 198         if (!log.equals(Arrays.asList("the annotation processor 2 is working!",
 199                                       "the annotation processor 1 is working!"))) {
 200             throw new AssertionError("Unexpected output: " + log);
 201         }
 202     }
 203 
 204     @Test
 205     public void testErrorOutputIfOneProcessorNameIsIncorrect(Path base) throws Exception {
 206         initialization(base);
 207         String log = new JavacTask(tb)
 208                 .options("-XDrawDiagnostics",
 209                          "--processor-module-path", processorCompiledModules.toString(),
 210                          "-processor", "mypkg2.MyProcessor2,noPackage.noProcessor,mypkg1.MyProcessor1")
 211                 .outdir(classes)
 212                 .sources(testClass)
 213                 .run(Task.Expect.FAIL)
 214                 .writeAll()
 215                 .getOutputLines(Task.OutputKind.STDOUT, Task.OutputKind.DIRECT).toString();
 216         if (!log.trim().equals("[the annotation processor 2 is working!, - compiler.err.proc.processor.not.found: noPackage.noProcessor, 1 error]")) {
 217             throw new AssertionError("Unexpected output: " + log);
 218         }
 219     }
 220 
 221     @Test
 222     public void testOptionsExclusion(Path base) throws Exception {
 223         initialization(base);
 224         List<String> log = new JavacTask(tb)
 225                 .options("-XDrawDiagnostics",
 226                         "--processor-module-path", processorCompiledModules.toString(),
 227                         "--processor-path", processorCompiledModules.toString())
 228                 .outdir(classes)
 229                 .sources(testClass)
 230                 .run(Task.Expect.FAIL)
 231                 .writeAll()
 232                 .getOutputLines(Task.OutputKind.DIRECT);
 233         if (!log.equals(Arrays.asList("- compiler.err.processorpath.no.processormodulepath",
 234                                       "1 error"))) {
 235             throw new AssertionError("Unexpected output: " + log);
 236         }
 237     }
 238 }