ApiExtraction.java revision 3573:c4a18ee691c4
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 * @bug 8054717
27 * @summary Make sure extraction of non-private APIs work as expected.
28 * @library /tools/lib
29 * @modules jdk.compiler/com.sun.tools.javac.api
30 *          jdk.compiler/com.sun.tools.javac.main
31 *          jdk.compiler/com.sun.tools.sjavac
32 *          jdk.compiler/com.sun.tools.sjavac.options
33 *          jdk.compiler/com.sun.tools.sjavac.pubapi
34 * @build Wrapper toolbox.ToolBox toolbox.JavacTask
35 * @run main Wrapper ApiExtraction
36 */
37
38import static java.util.Arrays.asList;
39import static java.util.Collections.emptyList;
40import static javax.lang.model.element.Modifier.FINAL;
41import static javax.lang.model.element.Modifier.PROTECTED;
42import static javax.lang.model.element.Modifier.PUBLIC;
43import static javax.lang.model.element.Modifier.STATIC;
44
45import java.io.IOException;
46import java.util.HashSet;
47import java.util.List;
48import java.util.Set;
49
50import javax.lang.model.type.TypeKind;
51
52import com.sun.tools.sjavac.PubApiExtractor;
53import com.sun.tools.sjavac.options.Options;
54import com.sun.tools.sjavac.pubapi.PrimitiveTypeDesc;
55import com.sun.tools.sjavac.pubapi.PubApi;
56import com.sun.tools.sjavac.pubapi.PubMethod;
57import com.sun.tools.sjavac.pubapi.PubType;
58import com.sun.tools.sjavac.pubapi.PubVar;
59import com.sun.tools.sjavac.pubapi.ReferenceTypeDesc;
60
61import toolbox.JavacTask;
62import toolbox.ToolBox;
63
64public class ApiExtraction {
65    public static void main(String[] args) throws IOException {
66
67        String testSrc = String.join("\n",
68                "import java.util.*;",
69                "public final class TestClass extends Thread {",
70
71                // Fields with various combination of modifiers
72                "    private String s1 = \"str 1\";",
73                "    public String s2 = \"str 2\";",
74                "    protected final String s3 = \"str 3\";",
75                "    static String s4 = \"str 4\";",
76
77                // Methods with various combinations of types and modifiers
78                "    protected void m1() {}",
79                "    public static Map<Integer, List<String>> m2() {",
80                "        return null;",
81                "    }",
82                "    final void m3(Set<Map<Integer, Map<String, String>>> s) {}",
83
84                // Some inner classes
85                "    static class DummyInner1 implements Runnable {",
86                "        protected int field;",
87                "        public void run() {}",
88                "    }",
89                "    final class DummyInner2 { }",
90                "}");
91
92        // Create class file to extract API from
93        new JavacTask(new ToolBox()).sources(testSrc).run();
94
95        // Extract PubApi
96        Options options = Options.parseArgs("-d", "bin", "--state-dir=bin", "-cp", ".");
97        PubApiExtractor pubApiExtr = new PubApiExtractor(options);
98        PubApi actualApi = pubApiExtr.getPubApi("TestClass");
99        pubApiExtr.close();
100
101        // Validate result
102        PubApi expectedApi = getExpectedPubApi();
103        if (!expectedApi.equals(actualApi)) {
104            List<String> diffs = expectedApi.diff(actualApi);
105            System.out.println(diffs.size() + " differences found.");
106            for (String diff : diffs) {
107                System.out.println(diff);
108            }
109            throw new AssertionError("Actual API differs from expected API.");
110        }
111    }
112
113    private static PubApi getExpectedPubApi() {
114
115        ReferenceTypeDesc string = new ReferenceTypeDesc("java.lang.String");
116
117        // Fields
118        // (s1 is private and therefore not included)
119        PubVar s2 = new PubVar(setOf(PUBLIC), string, "s2", null);
120        PubVar s4 = new PubVar(setOf(STATIC), string, "s4", null);
121        PubVar s3 = new PubVar(setOf(PROTECTED, FINAL), string, "s3",
122                                   "\"\\u0073\\u0074\\u0072\\u0020\\u0033\"");
123
124        // Methods
125        PubMethod init = new PubMethod(setOf(PUBLIC),
126                                       emptyList(),
127                                       new PrimitiveTypeDesc(TypeKind.VOID),
128                                       "<init>",
129                                       emptyList(),
130                                       emptyList());
131
132        PubMethod clinit = new PubMethod(setOf(STATIC),
133                                         emptyList(),
134                                         new PrimitiveTypeDesc(TypeKind.VOID),
135                                         "<clinit>",
136                                         emptyList(),
137                                         emptyList());
138
139        PubMethod m1 = new PubMethod(setOf(PROTECTED),
140                                     emptyList(),
141                                     new PrimitiveTypeDesc(TypeKind.VOID),
142                                     "m1",
143                                     emptyList(),
144                                     emptyList());
145
146        PubMethod m2 = new PubMethod(setOf(PUBLIC, STATIC),
147                                     emptyList(),
148                                     new ReferenceTypeDesc("java.util.Map"),
149                                     "m2",
150                                     emptyList(),
151                                     emptyList());
152
153        PubMethod m3 = new PubMethod(setOf(FINAL),
154                                     emptyList(),
155                                     new PrimitiveTypeDesc(TypeKind.VOID),
156                                     "m3",
157                                     asList(new ReferenceTypeDesc("java.util.Set")),
158                                     emptyList());
159
160        // Complete class
161        PubType testClass = new PubType(setOf(PUBLIC, FINAL),
162                                        "TestClass",
163                                        new PubApi(asList(getDummyInner1(), getDummyInner2()),
164                                                   asList(s2, s3, s4),
165                                                   asList(init, clinit, m1, m2, m3)));
166
167        // Wrap in "package level" PubApi
168        return new PubApi(asList(testClass), emptyList(), emptyList());
169    }
170
171    private static PubType getDummyInner1() {
172        PubMethod init = new PubMethod(setOf(),
173                                       emptyList(),
174                                       new PrimitiveTypeDesc(TypeKind.VOID),
175                                       "<init>",
176                                       emptyList(),
177                                       emptyList());
178
179        PubMethod run = new PubMethod(setOf(PUBLIC),
180                                      emptyList(),
181                                      new PrimitiveTypeDesc(TypeKind.VOID),
182                                      "run",
183                                      emptyList(),
184                                      emptyList());
185
186        PubVar field = new PubVar(setOf(PROTECTED),
187                                  new PrimitiveTypeDesc(TypeKind.INT),
188                                  "field",
189                                  null);
190
191        return new PubType(setOf(STATIC),
192                           "TestClass$DummyInner1",
193                           new PubApi(emptyList(),
194                                      asList(field),
195                                      asList(init, run)));
196    }
197
198    private static PubType getDummyInner2() {
199        PubMethod init = new PubMethod(setOf(),
200                                       emptyList(),
201                                       new PrimitiveTypeDesc(TypeKind.VOID),
202                                       "<init>",
203                                       emptyList(),
204                                       emptyList());
205
206        return new PubType(setOf(FINAL),
207                           "TestClass$DummyInner2",
208                           new PubApi(emptyList(),
209                                      emptyList(),
210                                      asList(init)));
211    }
212
213    @SafeVarargs
214    private static <T> Set<T> setOf(T... elements) {
215        return new HashSet<>(asList(elements));
216    }
217}
218