1 /* 2 * Copyright (c) 2011, 2013, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.sjavac.comp; 27 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.LinkedList; 33 import javax.lang.model.element.Modifier; 34 import javax.lang.model.element.ExecutableElement; 35 import javax.lang.model.element.TypeElement; 36 import javax.lang.model.element.VariableElement; 37 import javax.lang.model.type.TypeMirror; 38 import javax.lang.model.util.ElementScanner9; 39 40 /** Utility class that constructs a textual representation 41 * of the public api of a class. 42 * 43 * <p><b>This is NOT part of any supported API. 44 * If you write code that depends on this, you do so at your own 45 * risk. This code and its internal interfaces are subject to change 46 * or deletion without notice.</b></p> 47 */ 48 public class PubapiVisitor extends ElementScanner9<Void, Void> { 49 50 // The pubapi is stored here. 51 List<String> api = new LinkedList<String>(); 52 // The hash of the pubapi (excluding paths to jars/classes and their timestamp) 53 int hash; 54 // Indentation level. 55 int indent = 0; 56 // The class location info is for example: 57 // ZipFileIndexFileObject[/home/fredrik/bin/jdk1.8.0/lib/tools.jar(com/sun/tools/javac/comp/Resolve.class) 1396702502000 58 // ie the jfileobj.toString() + " " + jfileobj.getLastModified() 59 String class_loc_info = ""; 60 61 // If true, then store full public api information, not just the hash. 62 // Makes it much easier to debug any public api bugs. 63 boolean debugPubapi = false; 64 65 String depth(int l) { 66 return "________________________________".substring(0, l); 67 } 68 69 public void classLocInfo(String s) { 70 class_loc_info = " "+s; 71 } 72 73 public void construct(TypeElement e) { 74 visit(e); 75 hash = 0; 76 List<String> sorted_api = new ArrayList<>(); 77 sorted_api.addAll(api); 78 // Why sort here? Because we want the same pubapi hash to be generated 79 // for both a source compile and a classpath extraction. 80 Collections.sort(sorted_api); 81 82 for (String s : sorted_api) { 83 hash ^= s.hashCode(); 84 } 85 api = new LinkedList<String>(); 86 api.add(0, "PUBAPI "+e.getQualifiedName()+" "+Integer.toString(Math.abs(hash),16)+class_loc_info); 87 if (debugPubapi) { 88 api.addAll(sorted_api); 89 } 90 } 91 92 @Override 93 public Void visitType(TypeElement e, Void p) { 94 if (e.getModifiers().contains(Modifier.PUBLIC) 95 || e.getModifiers().contains(Modifier.PROTECTED)) 96 { 97 api.add(depth(indent) + "!TYPE " + e.getQualifiedName()); 98 indent += 2; 99 Void v = super.visitType(e, p); 100 indent -= 2; 101 return v; 102 } 103 return null; 104 } 105 106 @Override 107 public Void visitVariable(VariableElement e, Void p) { 108 if (e.getModifiers().contains(Modifier.PUBLIC) 109 || e.getModifiers().contains(Modifier.PROTECTED)) { 110 api.add(depth(indent)+"VAR "+makeVariableString(e)); 111 } 112 // Safe to not recurse here, because the only thing 113 // to visit here is the constructor of a variable declaration. 114 // If it happens to contain an anonymous inner class (which it might) 115 // then this class is never visible outside of the package anyway, so 116 // we are allowed to ignore it here. 117 return null; 118 } 119 120 @Override 121 public Void visitExecutable(ExecutableElement e, Void p) { 122 if (e.getModifiers().contains(Modifier.PUBLIC) 123 || e.getModifiers().contains(Modifier.PROTECTED)) { 124 api.add(depth(indent)+"METHOD "+makeMethodString(e)); 125 } 126 return null; 127 } 128 129 /** 130 * Creates a String representation of a method element with everything 131 * necessary to track all public aspects of it in an API. 132 * @param e Element to create String for. 133 * @return String representation of element. 134 */ 135 protected String makeMethodString(ExecutableElement e) { 136 StringBuilder result = new StringBuilder(); 137 for (Modifier modifier : e.getModifiers()) { 138 result.append(modifier.toString()); 139 result.append(" "); 140 } 141 result.append(e.getReturnType().toString()); 142 result.append(" "); 143 result.append(e.toString()); 144 145 List<? extends TypeMirror> thrownTypes = e.getThrownTypes(); 146 if (!thrownTypes.isEmpty()) { 147 result.append(" throws "); 148 for (Iterator<? extends TypeMirror> iterator = thrownTypes 149 .iterator(); iterator.hasNext();) { 150 TypeMirror typeMirror = iterator.next(); 151 result.append(typeMirror.toString()); 152 if (iterator.hasNext()) { 153 result.append(", "); 154 } 155 } 156 } 157 return result.toString(); 158 } 159 160 /** 161 * Creates a String representation of a variable element with everything 162 * necessary to track all public aspects of it in an API. 163 * @param e Element to create String for. 164 * @return String representation of element. 165 */ 166 protected String makeVariableString(VariableElement e) { 167 StringBuilder result = new StringBuilder(); 168 for (Modifier modifier : e.getModifiers()) { 169 result.append(modifier.toString()); 170 result.append(" "); 171 } 172 result.append(e.asType().toString()); 173 result.append(" "); 174 result.append(e.toString()); 175 Object value = e.getConstantValue(); 176 if (value != null) { 177 result.append(" = "); 178 if (e.asType().toString().equals("char")) { 179 int v = (int)value.toString().charAt(0); 180 result.append("'\\u"+Integer.toString(v,16)+"'"); 181 } else { 182 result.append(value.toString()); 183 } 184 } 185 return result.toString(); 186 } 187 }