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 
38 import static java.util.Arrays.asList;
39 import static java.util.Collections.emptyList;
40 import static javax.lang.model.element.Modifier.FINAL;
41 import static javax.lang.model.element.Modifier.PROTECTED;
42 import static javax.lang.model.element.Modifier.PUBLIC;
43 import static javax.lang.model.element.Modifier.STATIC;
44 
45 import java.io.IOException;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Set;
49 
50 import javax.lang.model.type.TypeKind;
51 
52 import com.sun.tools.sjavac.PubApiExtractor;
53 import com.sun.tools.sjavac.options.Options;
54 import com.sun.tools.sjavac.pubapi.PrimitiveTypeDesc;
55 import com.sun.tools.sjavac.pubapi.PubApi;
56 import com.sun.tools.sjavac.pubapi.PubMethod;
57 import com.sun.tools.sjavac.pubapi.PubType;
58 import com.sun.tools.sjavac.pubapi.PubVar;
59 import com.sun.tools.sjavac.pubapi.ReferenceTypeDesc;
60 
61 import toolbox.JavacTask;
62 import toolbox.ToolBox;
63 
64 public class ApiExtraction {
main(String[] args)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 
getExpectedPubApi()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 
getDummyInner1()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 
getDummyInner2()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
setOf(T... elements)214     private static <T> Set<T> setOf(T... elements) {
215         return new HashSet<>(asList(elements));
216     }
217 }
218