Source for gnu.java.lang.reflect.TypeSignature

   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:    */
  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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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