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