1 /* TypeSignature.java -- Class used to compute type signatures 2 Copyright (C) 1998, 2000, 2002 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.java.lang.reflect; 40 41 import gnu.java.lang.CPStringBuilder; 42 43 import java.lang.reflect.Constructor; 44 import java.lang.reflect.Field; 45 import java.lang.reflect.Member; 46 import java.lang.reflect.Method; 47 48 /** 49 * This class provides static methods that can be used to compute 50 * type-signatures of <code>Class</code>s or <code>Member</code>s. 51 * More specific methods are also provided for computing the 52 * type-signature of <code>Constructor</code>s and 53 * <code>Method</code>s. Methods are also provided to go in the 54 * reverse direction. 55 * 56 * @author Eric Blake (ebb9@email.byu.edu) 57 */ 58 public class TypeSignature 59 { 60 /** 61 * Returns a <code>String</code> representing the type-encoding of a class. 62 * The .class file format has different encodings for classes, depending 63 * on whether it must be disambiguated from primitive types or not; hence 64 * the descriptor parameter to choose between them. If you are planning 65 * on decoding primitive types along with classes, then descriptor should 66 * be true for correct results. Type-encodings are computed as follows: 67 * 68 * <pre> 69 * boolean -> "Z" 70 * byte -> "B" 71 * char -> "C" 72 * double -> "D" 73 * float -> "F" 74 * int -> "I" 75 * long -> "J" 76 * short -> "S" 77 * void -> "V" 78 * arrays -> "[" + descriptor format of component type 79 * object -> class format: fully qualified name with '.' replaced by '/' 80 * descriptor format: "L" + class format + ";" 81 * </pre> 82 * 83 * @param type the class name to encode 84 * @param descriptor true to return objects in descriptor format 85 * @return the class name, as it appears in bytecode constant pools 86 * @see #getClassForEncoding(String) 87 */ getEncodingOfClass(String type, boolean descriptor)88 public static String getEncodingOfClass(String type, boolean descriptor) 89 { 90 if (! descriptor || type.charAt(0) == '[') 91 return type.replace('.', '/'); 92 if (type.equals("boolean")) 93 return "Z"; 94 if (type.equals("byte")) 95 return "B"; 96 if (type.equals("short")) 97 return "S"; 98 if (type.equals("char")) 99 return "C"; 100 if (type.equals("int")) 101 return "I"; 102 if (type.equals("long")) 103 return "J"; 104 if (type.equals("float")) 105 return "F"; 106 if (type.equals("double")) 107 return "D"; 108 if (type.equals("void")) 109 return "V"; 110 return 'L' + type.replace('.', '/') + ';'; 111 } 112 113 /** 114 * Gets the descriptor encoding for a class. 115 * 116 * @param clazz the class to encode 117 * @param descriptor true to return objects in descriptor format 118 * @return the class name, as it appears in bytecode constant pools 119 * @see #getEncodingOfClass(String, boolean) 120 */ getEncodingOfClass(Class clazz, boolean descriptor)121 public static String getEncodingOfClass(Class clazz, boolean descriptor) 122 { 123 return getEncodingOfClass(clazz.getName(), descriptor); 124 } 125 126 /** 127 * Gets the descriptor encoding for a class. 128 * 129 * @param clazz the class to encode 130 * @return the class name, as it appears in bytecode constant pools 131 * @see #getEncodingOfClass(String, boolean) 132 */ getEncodingOfClass(Class clazz)133 public static String getEncodingOfClass(Class clazz) 134 { 135 return getEncodingOfClass(clazz.getName(), true); 136 } 137 138 139 /** 140 * This function is the inverse of <code>getEncodingOfClass</code>. This 141 * accepts both object and descriptor formats, but must know which style 142 * of string is being passed in (usually, descriptor should be true). In 143 * descriptor format, "I" is treated as int.class, in object format, it 144 * is treated as a class named I in the unnamed package. This method is 145 * strictly equivalent to {@link #getClassForEncoding(java.lang.String, boolean, java.lang.ClassLoader)} 146 * with a class loader equal to <code>null</code>. In that case, it 147 * uses the default class loader on the calling stack. 148 * 149 * @param type_code the class name to decode 150 * @param descriptor if the string is in descriptor format 151 * @return the corresponding Class object 152 * @throws ClassNotFoundException if the class cannot be located 153 * @see #getEncodingOfClass(Class, boolean) 154 */ getClassForEncoding(String type_code, boolean descriptor)155 public static Class getClassForEncoding(String type_code, boolean descriptor) 156 throws ClassNotFoundException 157 { 158 return getClassForEncoding(type_code, descriptor, null); 159 } 160 161 /** 162 * This function is the inverse of <code>getEncodingOfClass</code>. This 163 * accepts both object and descriptor formats, but must know which style 164 * of string is being passed in (usually, descriptor should be true). In 165 * descriptor format, "I" is treated as int.class, in object format, it 166 * is treated as a class named I in the unnamed package. 167 * 168 * @param type_code The class name to decode. 169 * @param descriptor If the string is in descriptor format. 170 * @param loader The class loader when resolving generic object name. If 171 * <code>loader</code> is null then it uses the default class loader on the 172 * calling stack. 173 * @return the corresponding Class object. 174 * @throws ClassNotFoundException if the class cannot be located. 175 * @see #getEncodingOfClass(Class, boolean) 176 * @see #getClassForEncoding(String, boolean) 177 */ getClassForEncoding(String type_code, boolean descriptor, ClassLoader loader)178 public static Class getClassForEncoding(String type_code, boolean descriptor, 179 ClassLoader loader) 180 throws ClassNotFoundException 181 { 182 if (descriptor) 183 { 184 switch (type_code.charAt(0)) 185 { 186 case 'B': 187 return byte.class; 188 case 'C': 189 return char.class; 190 case 'D': 191 return double.class; 192 case 'F': 193 return float.class; 194 case 'I': 195 return int.class; 196 case 'J': 197 return long.class; 198 case 'S': 199 return short.class; 200 case 'V': 201 return void.class; 202 case 'Z': 203 return boolean.class; 204 default: 205 throw new ClassNotFoundException("Invalid class name: " 206 + type_code); 207 case 'L': 208 type_code = type_code.substring(1, type_code.length() - 1); 209 // Fallthrough. 210 case '[': 211 } 212 } 213 return Class.forName(type_code.replace('/', '.'), true, loader); 214 } 215 216 /** 217 * Gets the Class object for a type name. 218 * 219 * @param type_code the class name to decode 220 * @return the corresponding Class object 221 * @throws ClassNotFoundException if the class cannot be located 222 * @see #getClassForEncoding(String, boolean) 223 */ getClassForEncoding(String type_code)224 public static Class getClassForEncoding(String type_code) 225 throws ClassNotFoundException 226 { 227 return getClassForEncoding(type_code, true); 228 } 229 230 /** 231 * Returns a <code>String</code> representing the type-encoding of a 232 * method. The type-encoding of a method is: 233 * 234 * "(" + parameter type descriptors + ")" + return type descriptor 235 * 236 * XXX This could be faster if it were implemented natively. 237 * 238 * @param m the method to encode 239 * @return the encoding 240 */ getEncodingOfMethod(Method m)241 public static String getEncodingOfMethod(Method m) 242 { 243 Class[] paramTypes = m.getParameterTypes(); 244 CPStringBuilder buf = new CPStringBuilder("("); 245 for (int i = 0; i < paramTypes.length; i++) 246 buf.append(getEncodingOfClass(paramTypes[i].getName(), true)); 247 buf.append(')').append(getEncodingOfClass(m.getReturnType().getName(), 248 true)); 249 return buf.toString(); 250 } 251 252 /** 253 * Returns a <code>String</code> representing the type-encoding of a 254 * constructor. The type-encoding of a method is: 255 * 256 * "(" + parameter type descriptors + ")V" 257 * 258 * XXX This could be faster if it were implemented natively. 259 * 260 * @param c the constructor to encode 261 * @return the encoding 262 */ getEncodingOfConstructor(Constructor c)263 public static String getEncodingOfConstructor(Constructor c) 264 { 265 Class[] paramTypes = c.getParameterTypes(); 266 CPStringBuilder buf = new CPStringBuilder("("); 267 for (int i = 0; i < paramTypes.length; i++) 268 buf.append(getEncodingOfClass(paramTypes[i].getName(), true)); 269 buf.append(")V"); 270 return buf.toString(); 271 } 272 273 /** 274 * Returns a <code>String</code> representing the type-encoding of a 275 * class member. This appropriately handles Constructors, Methods, and 276 * Fields. 277 * 278 * @param mem the member to encode 279 * @return the encoding 280 */ getEncodingOfMember(Member mem)281 public static String getEncodingOfMember(Member mem) 282 { 283 if (mem instanceof Constructor) 284 return getEncodingOfConstructor((Constructor) mem); 285 if (mem instanceof Method) 286 return getEncodingOfMethod((Method) mem); 287 else // Field 288 return getEncodingOfClass(((Field) mem).getType().getName(), true); 289 } 290 } // class TypeSignature 291