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 }