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 { 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 }