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