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