1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5/* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22package com.sun.org.apache.bcel.internal.generic; 23 24 25import com.sun.org.apache.bcel.internal.Constants; 26import com.sun.org.apache.bcel.internal.classfile.*; 27import java.util.ArrayList; 28 29/** 30 * Abstract super class for all possible java types, namely basic types 31 * such as int, object types like String and array types, e.g. int[] 32 * 33 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 34 */ 35public abstract class Type implements java.io.Serializable { 36 protected byte type; 37 protected String signature; // signature for the type 38 39 /** Predefined constants 40 */ 41 public static final BasicType VOID = new BasicType(Constants.T_VOID); 42 public static final BasicType BOOLEAN = new BasicType(Constants.T_BOOLEAN); 43 public static final BasicType INT = new BasicType(Constants.T_INT); 44 public static final BasicType SHORT = new BasicType(Constants.T_SHORT); 45 public static final BasicType BYTE = new BasicType(Constants.T_BYTE); 46 public static final BasicType LONG = new BasicType(Constants.T_LONG); 47 public static final BasicType DOUBLE = new BasicType(Constants.T_DOUBLE); 48 public static final BasicType FLOAT = new BasicType(Constants.T_FLOAT); 49 public static final BasicType CHAR = new BasicType(Constants.T_CHAR); 50 public static final ObjectType OBJECT = new ObjectType("java.lang.Object"); 51 public static final ObjectType STRING = new ObjectType("java.lang.String"); 52 public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer"); 53 public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable"); 54 public static final Type[] NO_ARGS = new Type[0]; 55 public static final ReferenceType NULL = new ReferenceType(){}; 56 public static final Type UNKNOWN = new Type(Constants.T_UNKNOWN, 57 "<unknown object>"){}; 58 59 protected Type(byte t, String s) { 60 type = t; 61 signature = s; 62 } 63 64 /** 65 * @return signature for given type. 66 */ 67 public String getSignature() { return signature; } 68 69 /** 70 * @return type as defined in Constants 71 */ 72 public byte getType() { return type; } 73 74 /** 75 * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise) 76 */ 77 public int getSize() { 78 switch(type) { 79 case Constants.T_DOUBLE: 80 case Constants.T_LONG: return 2; 81 case Constants.T_VOID: return 0; 82 default: return 1; 83 } 84 } 85 86 /** 87 * @return Type string, e.g. `int[]' 88 */ 89 public String toString() { 90 return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN)))? signature : 91 Utility.signatureToString(signature, false); 92 } 93 94 /** 95 * Convert type to Java method signature, e.g. int[] f(java.lang.String x) 96 * becomes (Ljava/lang/String;)[I 97 * 98 * @param return_type what the method returns 99 * @param arg_types what are the argument types 100 * @return method signature for given type(s). 101 */ 102 public static String getMethodSignature(Type return_type, Type[] arg_types) { 103 StringBuffer buf = new StringBuffer("("); 104 int length = (arg_types == null)? 0 : arg_types.length; 105 106 for(int i=0; i < length; i++) 107 buf.append(arg_types[i].getSignature()); 108 109 buf.append(')'); 110 buf.append(return_type.getSignature()); 111 112 return buf.toString(); 113 } 114 115 private static int consumed_chars=0; // Remember position in string, see getArgumentTypes 116 117 /** 118 * Convert signature to a Type object. 119 * @param signature signature string such as Ljava/lang/String; 120 * @return type object 121 */ 122 public static final Type getType(String signature) 123 throws StringIndexOutOfBoundsException 124 { 125 byte type = Utility.typeOfSignature(signature); 126 127 if(type <= Constants.T_VOID) { 128 consumed_chars = 1; 129 return BasicType.getType(type); 130 } else if(type == Constants.T_ARRAY) { 131 int dim=0; 132 do { // Count dimensions 133 dim++; 134 } while(signature.charAt(dim) == '['); 135 136 // Recurse, but just once, if the signature is ok 137 Type t = getType(signature.substring(dim)); 138 139 consumed_chars += dim; // update counter 140 141 return new ArrayType(t, dim); 142 } else { // type == T_REFERENCE 143 int index = signature.indexOf(';'); // Look for closing `;' 144 145 if(index < 0) 146 throw new ClassFormatException("Invalid signature: " + signature); 147 148 consumed_chars = index + 1; // "Lblabla;" `L' and `;' are removed 149 150 return new ObjectType(signature.substring(1, index).replace('/', '.')); 151 } 152 } 153 154 /** 155 * Convert return value of a method (signature) to a Type object. 156 * 157 * @param signature signature string such as (Ljava/lang/String;)V 158 * @return return type 159 */ 160 public static Type getReturnType(String signature) { 161 try { 162 // Read return type after `)' 163 int index = signature.lastIndexOf(')') + 1; 164 return getType(signature.substring(index)); 165 } catch(StringIndexOutOfBoundsException e) { // Should never occur 166 throw new ClassFormatException("Invalid method signature: " + signature); 167 } 168 } 169 170 /** 171 * Convert arguments of a method (signature) to an array of Type objects. 172 * @param signature signature string such as (Ljava/lang/String;)V 173 * @return array of argument types 174 */ 175 public static Type[] getArgumentTypes(String signature) { 176 ArrayList vec = new ArrayList(); 177 int index; 178 Type[] types; 179 180 try { // Read all declarations between for `(' and `)' 181 if(signature.charAt(0) != '(') 182 throw new ClassFormatException("Invalid method signature: " + signature); 183 184 index = 1; // current string position 185 186 while(signature.charAt(index) != ')') { 187 vec.add(getType(signature.substring(index))); 188 index += consumed_chars; // update position 189 } 190 } catch(StringIndexOutOfBoundsException e) { // Should never occur 191 throw new ClassFormatException("Invalid method signature: " + signature); 192 } 193 194 types = new Type[vec.size()]; 195 vec.toArray(types); 196 return types; 197 } 198 199 /** Convert runtime java.lang.Class to BCEL Type object. 200 * @param cl Java class 201 * @return corresponding Type object 202 */ 203 public static Type getType(java.lang.Class cl) { 204 if(cl == null) { 205 throw new IllegalArgumentException("Class must not be null"); 206 } 207 208 /* That's an amzingly easy case, because getName() returns 209 * the signature. That's what we would have liked anyway. 210 */ 211 if(cl.isArray()) { 212 return getType(cl.getName()); 213 } else if(cl.isPrimitive()) { 214 if(cl == Integer.TYPE) { 215 return INT; 216 } else if(cl == Void.TYPE) { 217 return VOID; 218 } else if(cl == Double.TYPE) { 219 return DOUBLE; 220 } else if(cl == Float.TYPE) { 221 return FLOAT; 222 } else if(cl == Boolean.TYPE) { 223 return BOOLEAN; 224 } else if(cl == Byte.TYPE) { 225 return BYTE; 226 } else if(cl == Short.TYPE) { 227 return SHORT; 228 } else if(cl == Byte.TYPE) { 229 return BYTE; 230 } else if(cl == Long.TYPE) { 231 return LONG; 232 } else if(cl == Character.TYPE) { 233 return CHAR; 234 } else { 235 throw new IllegalStateException("Ooops, what primitive type is " + cl); 236 } 237 } else { // "Real" class 238 return new ObjectType(cl.getName()); 239 } 240 } 241 242 public static String getSignature(java.lang.reflect.Method meth) { 243 StringBuffer sb = new StringBuffer("("); 244 Class[] params = meth.getParameterTypes(); // avoid clone 245 246 for(int j = 0; j < params.length; j++) { 247 sb.append(getType(params[j]).getSignature()); 248 } 249 250 sb.append(")"); 251 sb.append(getType(meth.getReturnType()).getSignature()); 252 return sb.toString(); 253 } 254} 255