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 java.lang.reflect.Constructor; 42 import java.lang.reflect.Field; 43 import java.lang.reflect.Member; 44 import java.lang.reflect.Method; 45 46 /** 47 * This class provides static methods that can be used to compute 48 * type-signatures of <code>Class</code>s or <code>Member</code>s. 49 * More specific methods are also provided for computing the 50 * type-signature of <code>Constructor</code>s and 51 * <code>Method</code>s. Methods are also provided to go in the 52 * reverse direction. 53 * 54 * @author Eric Blake (ebb9@email.byu.edu) 55 */ 56 public class TypeSignature 57 { 58 /** 59 * Returns a <code>String</code> representing the type-encoding of a class. 60 * The .class file format has different encodings for classes, depending 61 * on whether it must be disambiguated from primitive types or not; hence 62 * the descriptor parameter to choose between them. If you are planning 63 * on decoding primitive types along with classes, then descriptor should 64 * be true for correct results. Type-encodings are computed as follows: 65 * 66 * <pre> 67 * boolean -> "Z" 68 * byte -> "B" 69 * char -> "C" 70 * double -> "D" 71 * float -> "F" 72 * int -> "I" 73 * long -> "J" 74 * short -> "S" 75 * void -> "V" 76 * arrays -> "[" + descriptor format of component type 77 * object -> class format: fully qualified name with '.' replaced by '/' 78 * descriptor format: "L" + class format + ";" 79 * </pre> 80 * 81 * @param type the class name to encode 82 * @param descriptor true to return objects in descriptor format 83 * @return the class name, as it appears in bytecode constant pools 84 * @see #getClassForEncoding(String) 85 */ getEncodingOfClass(String type, boolean descriptor)86 public static String getEncodingOfClass(String type, boolean descriptor) 87 { 88 if (! descriptor || type.charAt(0) == '[') 89 return type.replace('.', '/'); 90 if (type.equals("boolean")) 91 return "Z"; 92 if (type.equals("byte")) 93 return "B"; 94 if (type.equals("short")) 95 return "S"; 96 if (type.equals("char")) 97 return "C"; 98 if (type.equals("int")) 99 return "I"; 100 if (type.equals("long")) 101 return "J"; 102 if (type.equals("float")) 103 return "F"; 104 if (type.equals("double")) 105 return "D"; 106 if (type.equals("void")) 107 return "V"; 108 return 'L' + type.replace('.', '/') + ';'; 109 } 110 111 /** 112 * Gets the descriptor encoding for a class. 113 * 114 * @param clazz the class to encode 115 * @param descriptor true to return objects in descriptor format 116 * @return the class name, as it appears in bytecode constant pools 117 * @see #getEncodingOfClass(String, boolean) 118 */ getEncodingOfClass(Class clazz, boolean descriptor)119 public static String getEncodingOfClass(Class clazz, boolean descriptor) 120 { 121 return getEncodingOfClass(clazz.getName(), descriptor); 122 } 123 124 /** 125 * Gets the descriptor encoding for a class. 126 * 127 * @param clazz the class to encode 128 * @return the class name, as it appears in bytecode constant pools 129 * @see #getEncodingOfClass(String, boolean) 130 */ getEncodingOfClass(Class clazz)131 public static String getEncodingOfClass(Class clazz) 132 { 133 return getEncodingOfClass(clazz.getName(), true); 134 } 135 136 137 /** 138 * This function is the inverse of <code>getEncodingOfClass</code>. This 139 * accepts both object and descriptor formats, but must know which style 140 * of string is being passed in (usually, descriptor should be true). In 141 * descriptor format, "I" is treated as int.class, in object format, it 142 * is treated as a class named I in the unnamed package. This method is 143 * strictly equivalent to {@link #getClassForEncoding(java.lang.String, boolean, java.lang.ClassLoader)} 144 * with a class loader equal to <code>null</code>. In that case, it 145 * uses the default class loader on the calling stack. 146 * 147 * @param type_code the class name to decode 148 * @param descriptor if the string is in descriptor format 149 * @return the corresponding Class object 150 * @throws ClassNotFoundException if the class cannot be located 151 * @see #getEncodingOfClass(Class, boolean) 152 */ getClassForEncoding(String type_code, boolean descriptor)153 public static Class getClassForEncoding(String type_code, boolean descriptor) 154 throws ClassNotFoundException 155 { 156 return getClassForEncoding(type_code, descriptor, null); 157 } 158 159 /** 160 * This function is the inverse of <code>getEncodingOfClass</code>. This 161 * accepts both object and descriptor formats, but must know which style 162 * of string is being passed in (usually, descriptor should be true). In 163 * descriptor format, "I" is treated as int.class, in object format, it 164 * is treated as a class named I in the unnamed package. 165 * 166 * @param type_code The class name to decode. 167 * @param descriptor If the string is in descriptor format. 168 * @param loader The class loader when resolving generic object name. If 169 * <code>loader</code> is null then it uses the default class loader on the 170 * calling stack. 171 * @return the corresponding Class object. 172 * @throws ClassNotFoundException if the class cannot be located. 173 * @see #getEncodingOfClass(Class, boolean) 174 * @see #getClassForEncoding(String, boolean) 175 */ getClassForEncoding(String type_code, boolean descriptor, ClassLoader loader)176 public static Class getClassForEncoding(String type_code, boolean descriptor, 177 ClassLoader loader) 178 throws ClassNotFoundException 179 { 180 if (descriptor) 181 { 182 switch (type_code.charAt(0)) 183 { 184 case 'B': 185 return byte.class; 186 case 'C': 187 return char.class; 188 case 'D': 189 return double.class; 190 case 'F': 191 return float.class; 192 case 'I': 193 return int.class; 194 case 'J': 195 return long.class; 196 case 'S': 197 return short.class; 198 case 'V': 199 return void.class; 200 case 'Z': 201 return boolean.class; 202 default: 203 throw new ClassNotFoundException("Invalid class name: " 204 + type_code); 205 case 'L': 206 type_code = type_code.substring(1, type_code.length() - 1); 207 // Fallthrough. 208 case '[': 209 } 210 } 211 return Class.forName(type_code.replace('/', '.'), true, loader); 212 } 213 214 /** 215 * Gets the Class object for a type name. 216 * 217 * @param type_code the class name to decode 218 * @return the corresponding Class object 219 * @throws ClassNotFoundException if the class cannot be located 220 * @see #getClassForEncoding(String, boolean) 221 */ getClassForEncoding(String type_code)222 public static Class getClassForEncoding(String type_code) 223 throws ClassNotFoundException 224 { 225 return getClassForEncoding(type_code, true); 226 } 227 228 /** 229 * Returns a <code>String</code> representing the type-encoding of a 230 * method. The type-encoding of a method is: 231 * 232 * "(" + parameter type descriptors + ")" + return type descriptor 233 * 234 * XXX This could be faster if it were implemented natively. 235 * 236 * @param m the method to encode 237 * @return the encoding 238 */ getEncodingOfMethod(Method m)239 public static String getEncodingOfMethod(Method m) 240 { 241 Class[] paramTypes = m.getParameterTypes(); 242 StringBuffer buf = new StringBuffer().append('('); 243 for (int i = 0; i < paramTypes.length; i++) 244 buf.append(getEncodingOfClass(paramTypes[i].getName(), true)); 245 buf.append(')').append(getEncodingOfClass(m.getReturnType().getName(), 246 true)); 247 return buf.toString(); 248 } 249 250 /** 251 * Returns a <code>String</code> representing the type-encoding of a 252 * constructor. The type-encoding of a method is: 253 * 254 * "(" + parameter type descriptors + ")V" 255 * 256 * XXX This could be faster if it were implemented natively. 257 * 258 * @param c the constructor to encode 259 * @return the encoding 260 */ getEncodingOfConstructor(Constructor c)261 public static String getEncodingOfConstructor(Constructor c) 262 { 263 Class[] paramTypes = c.getParameterTypes(); 264 StringBuffer buf = new StringBuffer().append('('); 265 for (int i = 0; i < paramTypes.length; i++) 266 buf.append(getEncodingOfClass(paramTypes[i].getName(), true)); 267 buf.append(")V"); 268 return buf.toString(); 269 } 270 271 /** 272 * Returns a <code>String</code> representing the type-encoding of a 273 * class member. This appropriately handles Constructors, Methods, and 274 * Fields. 275 * 276 * @param mem the member to encode 277 * @return the encoding 278 */ getEncodingOfMember(Member mem)279 public static String getEncodingOfMember(Member mem) 280 { 281 if (mem instanceof Constructor) 282 return getEncodingOfConstructor((Constructor) mem); 283 if (mem instanceof Method) 284 return getEncodingOfMethod((Method) mem); 285 else // Field 286 return getEncodingOfClass(((Field) mem).getType().getName(), true); 287 } 288 } // class TypeSignature 289