AddLimitMods.java revision 3376:4c740bddc648
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 -addmods and -limitmods; 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    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("-modulesourcepath", moduleSrc.toString())
107                .outdir(modulePath)
108                .files(findJavaFiles(m3))
109                .run()
110                .writeAll();
111
112        new JavacTask(tb)
113                .options("-modulesourcepath", moduleSrc.toString())
114                .outdir(modulePath)
115                .files(findJavaFiles(m2))
116                .run()
117                .writeAll();
118
119        //real test
120        new JavacTask(tb)
121                .options("-modulepath", modulePath.toString(),
122                         "-XDshouldStopPolicyIfNoError=FLOW",
123                         "-limitmods", "java.base")
124                .outdir(modulePath)
125                .files(findJavaFiles(m1))
126                .run(Task.Expect.FAIL)
127                .writeAll();
128
129        new JavacTask(tb)
130                .options("-modulepath", modulePath.toString(),
131                         "-XDshouldStopPolicyIfNoError=FLOW",
132                         "-limitmods", "java.base",
133                         "-addmods", "m2")
134                .outdir(modulePath)
135                .files(findJavaFiles(m1))
136                .run(Task.Expect.FAIL)
137                .writeAll();
138
139        new JavacTask(tb)
140                .options("-modulepath", modulePath.toString(),
141                         "-XDshouldStopPolicyIfNoError=FLOW",
142                         "-limitmods", "java.base",
143                         "-addmods", "m2,m3")
144                .outdir(modulePath)
145                .files(findJavaFiles(m1))
146                .run()
147                .writeAll();
148
149        new JavacTask(tb)
150                .options("-modulepath", modulePath.toString(),
151                         "-XDshouldStopPolicyIfNoError=FLOW",
152                         "-limitmods", "m2")
153                .outdir(modulePath)
154                .files(findJavaFiles(m1))
155                .run()
156                .writeAll();
157
158        new JavacTask(tb)
159                .options("-modulepath", modulePath.toString(),
160                         "-XDshouldStopPolicyIfNoError=FLOW",
161                         "-limitmods", "m3")
162                .outdir(modulePath)
163                .files(findJavaFiles(m1))
164                .run(Task.Expect.FAIL)
165                .writeAll();
166
167        new JavacTask(tb)
168                .options("-modulepath", modulePath.toString(),
169                         "-XDshouldStopPolicyIfNoError=FLOW",
170                         "-limitmods", "m3",
171                         "-addmods", "m2")
172                .outdir(modulePath)
173                .files(findJavaFiles(m1))
174                .run()
175                .writeAll();
176    }
177
178    @Test
179    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[] {"-addmods", "java.annotations.common,java.xml.bind"},
223                                              null),
224            new SimpleEntry<String[], String>(new String[] {"-limitmods", "java.xml.ws,jdk.compiler"},
225                                              null),
226            new SimpleEntry<String[], String>(new String[] {"-addmods", "ALL-SYSTEM"},
227                                              null)
228    );
229
230    @Test
231    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("-modulesourcepath", 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("-modulepath", modulePath.toString())
262                .outdir(cpOut)
263                .files(findJavaFiles(cpSrc))
264                .run(Task.Expect.FAIL)
265                .writeAll();
266
267        new JavacTask(tb)
268                .options("-modulepath", modulePath.toString(),
269                         "-addmods", "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("-modulesourcepath", moduleSrc.toString(),
282                            "-XDrawDiagnostics",
283                            "-addmods", "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                            "-addmods", "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                            "-addmods", "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 -addmods 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                            "-addmods", "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    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        new JavacTask(tb)
349                .outdir(classpathOut)
350                .files(findJavaFiles(classpathSrc))
351                .run()
352                .writeAll()
353                .getOutput(Task.OutputKind.DIRECT);
354
355        Path automaticSrc = base.resolve("automatic-src");
356        Path automaticOut = base.resolve("automatic-out");
357
358        tb.writeJavaFiles(automaticSrc,
359                          generateCheckAccessibleClass("automatic.Automatic"));
360
361        Files.createDirectories(automaticOut);
362
363        new JavacTask(tb)
364                .outdir(automaticOut)
365                .files(findJavaFiles(automaticSrc))
366                .run()
367                .writeAll()
368                .getOutput(Task.OutputKind.DIRECT);
369
370        Path modulePath = base.resolve("module-path");
371
372        Files.createDirectories(modulePath);
373
374        Path automaticJar = modulePath.resolve("automatic.jar");
375
376        new JarTask(tb, automaticJar)
377          .baseDir(automaticOut)
378          .files("automatic/Automatic.class")
379          .run();
380
381        Path moduleSrc = base.resolve("module-src");
382        Path m1 = moduleSrc.resolve("m1");
383
384        tb.writeJavaFiles(m1,
385                          "module m1 { exports api; }",
386                          "package api; public class Api { public void test() { } }");
387
388        new JavacTask(tb)
389                .options("-modulesourcepath", moduleSrc.toString())
390                .outdir(modulePath)
391                .files(findJavaFiles(moduleSrc))
392                .run()
393                .writeAll()
394                .getOutput(Task.OutputKind.DIRECT);
395
396        int index = 0;
397
398        for (String moduleInfo : MODULE_INFO_VARIANTS) {
399            for (String[] options : OPTIONS_VARIANTS) {
400                index++;
401
402                System.err.println("running check: " + moduleInfo + "; " + Arrays.asList(options));
403
404                Path m2Runtime = base.resolve(index + "-runtime").resolve("m2");
405                Path out = base.resolve(index + "-runtime").resolve("out").resolve("m2");
406
407                Files.createDirectories(out);
408
409                StringBuilder testClassNamed = new StringBuilder();
410
411                testClassNamed.append("package test;\n" +
412                                      "public class Test {\n" +
413                                      "    public static void main(String... args) throws Exception {\n");
414
415                for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) {
416                    testClassNamed.append("        System.err.println(\"visible:" + e.getKey() + ":\" + java.lang.reflect.Layer.boot().findModule(\"" + e.getKey() + "\").isPresent());\n");
417                }
418
419                testClassNamed.append("        Class<?> cp = Class.forName(Test.class.getClassLoader().getUnnamedModule(), \"cp.CP\");\n");
420                testClassNamed.append("        cp.getDeclaredMethod(\"runMe\").invoke(null);\n");
421
422                testClassNamed.append("        Class<?> automatic = Class.forName(java.lang.reflect.Layer.boot().findModule(\"automatic\").get(), \"automatic.Automatic\");\n");
423                testClassNamed.append("        automatic.getDeclaredMethod(\"runMe\").invoke(null);\n");
424
425                testClassNamed.append("    }\n" +
426                                      "}");
427
428                tb.writeJavaFiles(m2Runtime, moduleInfo, testClassNamed.toString());
429
430                new JavacTask(tb)
431                   .options("-modulepath", modulePath.toString())
432                   .outdir(out)
433                   .files(findJavaFiles(m2Runtime))
434                   .run()
435                   .writeAll();
436
437                boolean success;
438                String output;
439
440                try {
441                    output = new JavaTask(tb)
442                       .vmOptions(augmentOptions(options,
443                                                 Collections.emptyList(),
444                                                 "-modulepath", modulePath.toString() + File.pathSeparator + out.getParent().toString(),
445                                                 "-classpath", classpathOut.toString(),
446                                                 "-XaddReads:m2=ALL-UNNAMED,automatic",
447                                                 "-m", "m2/test.Test"))
448                       .run()
449                       .writeAll()
450                       .getOutput(Task.OutputKind.STDERR);
451
452                    success = true;
453                } catch (Task.TaskError err) {
454                    success = false;
455                    output = "";
456                }
457
458                Path m2 = base.resolve(String.valueOf(index)).resolve("m2");
459
460                tb.writeJavaFiles(m2,
461                                  moduleInfo,
462                                  "package test;\n" +
463                                  "public class Test {}\n");
464
465                List<String> auxOptions = success ? Arrays.asList(
466                    "-processorpath", System.getProperty("test.class.path"),
467                    "-processor", CheckVisibleModule.class.getName(),
468                    "-Aoutput=" + output,
469                    "-XDaccessInternalAPI=true"
470                ) : Collections.emptyList();
471                new JavacTask(tb)
472                   .options(augmentOptions(options,
473                                           auxOptions,
474                                           "-modulepath", modulePath.toString(),
475                                           "-classpath", classpathOut.toString(),
476                                           "-XDshouldStopPolicyIfNoError=FLOW"))
477                   .outdir(modulePath)
478                   .files(findJavaFiles(m2))
479                   .run(success ? Task.Expect.SUCCESS : Task.Expect.FAIL)
480                   .writeAll();
481            }
482        }
483    }
484
485    private String generateCheckAccessibleClass(String fqn) {
486        String packageName = fqn.substring(0, fqn.lastIndexOf('.'));
487        String simpleName = fqn.substring(fqn.lastIndexOf('.') + 1);
488        StringBuilder checkClassesAccessible = new StringBuilder();
489        checkClassesAccessible.append("package " + packageName + ";" +
490                                      "public class " + simpleName + " {" +
491                                      "    public static void runMe() throws Exception {");
492        for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) {
493            checkClassesAccessible.append("try {");
494            checkClassesAccessible.append("Class.forName(\"" + e.getValue() + "\").newInstance();");
495            checkClassesAccessible.append("System.err.println(\"" + fqn + ":" + e.getKey() + ":true\");");
496            checkClassesAccessible.append("} catch (Exception ex) {");
497            checkClassesAccessible.append("System.err.println(\"" + fqn + ":" + e.getKey() + ":false\");");
498            checkClassesAccessible.append("}");
499        }
500
501        checkClassesAccessible.append("    }\n" +
502                                      "}");
503
504        return checkClassesAccessible.toString();
505    }
506
507    private static final Map<String, String> MODULES_TO_CHECK_TO_SAMPLE_CLASS = new LinkedHashMap<>();
508
509    static {
510        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m1", "api.Api");
511        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m2", "test.Test");
512        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.base", "java.lang.Object");
513        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.compiler", "javax.tools.ToolProvider");
514        MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("jdk.compiler", "com.sun.tools.javac.Main");
515    };
516
517    @SupportedAnnotationTypes("*")
518    @SupportedOptions("output")
519    public static final class CheckVisibleModule extends AbstractProcessor {
520
521        @Override
522        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
523            String expected = processingEnv.getOptions().get("output");
524            Set<String> expectedElements = new HashSet<>(Arrays.asList(expected.split(System.getProperty("line.separator"))));
525            Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
526            Symtab syms = Symtab.instance(context);
527
528            for (Entry<String, String> e : MODULES_TO_CHECK_TO_SAMPLE_CLASS.entrySet()) {
529                String module = e.getKey();
530                ModuleElement mod = processingEnv.getElementUtils().getModuleElement(module);
531                String visible = "visible:" + module + ":" + (mod != null);
532
533                if (!expectedElements.contains(visible)) {
534                    throw new AssertionError("actual: " + visible + "; expected: " + expected);
535                }
536
537                JavacElements javacElements = JavacElements.instance(context);
538                ClassSymbol unnamedClass = javacElements.getTypeElement(syms.unnamedModule, e.getValue());
539                String unnamed = "cp.CP:" + module + ":" + (unnamedClass != null);
540
541                if (!expectedElements.contains(unnamed)) {
542                    throw new AssertionError("actual: " + unnamed + "; expected: " + expected);
543                }
544
545                ModuleElement automaticMod = processingEnv.getElementUtils().getModuleElement("automatic");
546                ClassSymbol automaticClass = javacElements.getTypeElement(automaticMod, e.getValue());
547                String automatic = "automatic.Automatic:" + module + ":" + (automaticClass != null);
548
549                if (!expectedElements.contains(automatic)) {
550                    throw new AssertionError("actual: " + automatic + "; expected: " + expected);
551                }
552            }
553
554            return false;
555        }
556
557        @Override
558        public SourceVersion getSupportedSourceVersion() {
559            return SourceVersion.latest();
560        }
561
562    }
563
564    public String[] augmentOptions(String[] options, List<String> auxOptions, String... baseOptions) {
565        List<String> all = new ArrayList<>();
566
567        all.addAll(Arrays.asList(options));
568        all.addAll(Arrays.asList(baseOptions));
569        all.addAll(auxOptions);
570
571        return all.toArray(new String[0]);
572    }
573
574    private static final String[] MODULE_INFO_VARIANTS = {
575        "module m2 { exports test; }",
576        "module m2 { requires m1; exports test; }",
577        "module m2 { requires jdk.compiler; exports test; }",
578    };
579
580    private static final String[][] OPTIONS_VARIANTS = {
581        {"-addmods", "automatic"},
582        {"-addmods", "m1,automatic"},
583        {"-addmods", "jdk.compiler,automatic"},
584        {"-addmods", "m1,jdk.compiler,automatic"},
585        {"-addmods", "ALL-SYSTEM,automatic"},
586        {"-limitmods", "java.base", "-addmods", "automatic"},
587        {"-limitmods", "java.base", "-addmods", "ALL-SYSTEM,automatic"},
588        {"-limitmods", "m2", "-addmods", "automatic"},
589        {"-limitmods", "jdk.compiler", "-addmods", "automatic"},
590    };
591}
592