001 package edu.rice.cs.cunit.subAnnot; 002 003 import edu.rice.cs.cunit.classFile.attributes.AAnnotationsAttributeInfo; 004 import edu.rice.cs.cunit.classFile.attributes.AMultipleNamedAnnotationsAttributeInfo; 005 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleLocalVariableAnnotationsAttributeInfo; 006 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleParameterAnnotationsAttributeInfo; 007 008 import java.lang.annotation.Annotation; 009 import java.lang.reflect.*; 010 import java.util.ArrayList; 011 import java.util.HashMap; 012 import java.util.List; 013 import java.util.Map; 014 015 /** 016 * Extended Constructor class to support annotations with subclassing. 017 * 018 * @author Mathias Ricken 019 */ 020 public class ConstructorEx<T> extends AAnnotatedElementEx { 021 /** 022 * The java.lang.reflect.Constructor object that represents the constructor. 023 */ 024 public final Constructor<T> java; 025 026 /** 027 * Parameter annotation attribute. 028 */ 029 private RuntimeVisibleParameterAnnotationsAttributeInfo _pai; 030 031 /** 032 * Local variable annotation attribute. 033 */ 034 private RuntimeVisibleLocalVariableAnnotationsAttributeInfo _lvai; 035 036 /** 037 * Create an extended Constructor instance for the specified c. 038 * @param c constructor. 039 */ 040 public ConstructorEx(Constructor<T> c) { 041 this(c, null); 042 } 043 /** 044 * Create an extended Constructor instance for the specified c. 045 * @param c constructor. 046 * @param cl class loader 047 */ 048 public ConstructorEx(Constructor<T> c, ClassLoader cl) { 049 super(cl); 050 java = c; 051 findMethodAnnotationsAttributeInfo(c, "<init>", c.getParameterTypes()); 052 _pai = getParameterAnnotationsAttributeInfo(c, "<init>", c.getParameterTypes()); 053 _lvai = getLocalVarAnnotationsAttributeInfo(c, "<init>", c.getParameterTypes()); 054 } 055 056 057 /** 058 * Return the annotated element. 059 * @return annotated element 060 */ 061 protected AnnotatedElement getAnnotatedElement() { 062 return java; 063 } 064 065 /** 066 * Returns the name of this constructor, as a string. This is always the same as the simple name of the 067 * constructor's declaring class. 068 * @return name 069 */ 070 public String getName() { 071 return java.getName(); 072 } 073 074 /** 075 * Returns the Java language modifiers for the constructor represented by this <code>Constructor</code> object, as 076 * an integer. The <code>Modifier</code> class should be used to decode the modifiers. 077 * @return modifiers 078 * @see java.lang.reflect.Modifier 079 */ 080 public int getModifiers() { 081 return java.getModifiers(); 082 } 083 084 /** 085 * Returns an array of <tt>TypeVariable</tt> objects that represent the type variables declared by the generic 086 * declaration represented by this <tt>GenericDeclaration</tt> object, in declaration order. Returns an array of 087 * length 0 if the underlying generic declaration declares no type variables. 088 * 089 * @return an array of <tt>TypeVariable</tt> objects that represent the type variables declared by this generic 090 * declaration 091 * 092 * @throws java.lang.reflect.GenericSignatureFormatError 093 * if the generic signature of this generic declaration does not conform to the format specified in the Java 094 * Virtual Machine Specification, 3rd edition 095 */ 096 public TypeVariable[] getTypeParameters() { 097 return java.getTypeParameters(); 098 } 099 100 /** 101 * Returns an array of <tt>Type</tt> objects that represent the formal parameter types, in declaration order, of the 102 * method represented by this <tt>Constructor</tt> object. Returns an array of length 0 if the underlying method takes 103 * no parameters. 104 * <p/> 105 * <p>If a formal parameter type is a parameterized type, the <tt>Type</tt> object returned for it must accurately 106 * reflect the actual type parameters used in the source code. 107 * <p/> 108 * <p>If a formal parameter type is a type variable or a parameterized type, it is created. Otherwise, it is resolved. 109 * 110 * @return an array of <tt>Type</tt>s that represent the formal parameter types of the underlying method, in 111 * declaration order 112 * 113 * @throws java.lang.reflect.GenericSignatureFormatError 114 * if the generic method signature does not conform to the format specified in the Java 115 * Virtual Machine Specification, 3rd edition 116 * @throws TypeNotPresentException if any of the parameter types of the underlying method refers to a non-existent type 117 * declaration 118 * @throws java.lang.reflect.MalformedParameterizedTypeException 119 * if any of the underlying method's parameter types refer to a parameterized type that 120 * cannot be instantiated for any reason 121 */ 122 public Type[] getGenericParameterTypes() { 123 return java.getGenericParameterTypes(); 124 } 125 126 /** 127 * Returns an array of <code>Class</code> objects that represent the types of exceptions declared to be thrown by 128 * the underlying constructor represented by this <code>Constructor</code> object. Returns an array of length 0 if 129 * the constructor declares no exceptions in its <code>throws</code> clause. 130 * 131 * @return the exception types declared as being thrown by the constructor this object represents 132 */ 133 @SuppressWarnings("unchecked") 134 public ClassEx[] getExceptionTypes() { 135 List<ClassEx> list = new ArrayList<ClassEx>(); 136 for(Class c: java.getExceptionTypes()) { 137 list.add(new ClassEx(c, _classLoader)); 138 } 139 return list.toArray(new ClassEx[list.size()]); 140 } 141 142 /** 143 * Returns an array of <tt>Type</tt> objects that represent the exceptions declared to be thrown by this 144 * <tt>Constructor</tt> object. Returns an array of length 0 if the underlying method declares no exceptions in its 145 * <tt>throws</tt> clause. 146 * <p/> 147 * <p>If an exception type is a parameterized type, the <tt>Type</tt> object returned for it must accurately reflect 148 * the actual type parameters used in the source code. 149 * <p/> 150 * <p>If an exception type is a type variable or a parameterized type, it is created. Otherwise, it is resolved. 151 * 152 * @return an array of Types that represent the exception types thrown by the underlying method 153 * 154 * @throws java.lang.reflect.GenericSignatureFormatError 155 * if the generic method signature does not conform to the format specified in the Java 156 * Virtual Machine Specification, 3rd edition 157 * @throws TypeNotPresentException if the underlying method's <tt>throws</tt> clause refers to a non-existent type 158 * declaration 159 * @throws java.lang.reflect.MalformedParameterizedTypeException 160 * if the underlying method's <tt>throws</tt> clause refers to a parameterized type 161 * that cannot be instantiated for any reason 162 */ 163 public Type[] getGenericExceptionTypes() { 164 return java.getGenericExceptionTypes(); 165 } 166 167 /** 168 * Compares this <code>Constructor</code> against the specified object. Returns true if the objects are the same. Two 169 * <code>Constructor</code> objects are the same if they were declared by the same class and have the same formal 170 * parameter types. 171 */ 172 public boolean equals(Object obj) { 173 return (obj!=null)&&(obj.getClass().equals(this.getClass()) && (java.equals(obj))); 174 } 175 176 /** 177 * Returns a hashcode for this <code>Constructor</code>. The hashcode is the same as the hashcode for the underlying 178 * constructor's declaring class name. 179 */ 180 public int hashCode() { 181 return java.hashCode(); 182 } 183 184 /** 185 * Returns a string describing this <code>Constructor</code>. The string is formatted as the constructor access 186 * modifiers, if any, followed by the fully-qualified name of the declaring class, followed by a parenthesized, 187 * comma-separated list of the constructor's formal parameter types. For example: 188 * <pre> 189 * public java.util.Hashtable(int,float) 190 * </pre> 191 * <p/> 192 * <p>The only possible modifiers for constructors are the access modifiers <tt>public</tt>, <tt>protected</tt> or 193 * <tt>private</tt>. Only one of these may appear, or none if the constructor has default (package) access. 194 */ 195 public String toString() { 196 return java.toString(); 197 } 198 199 /** 200 * Returns a string describing this <code>Constructor</code>, including type parameters. The string is formatted as 201 * the constructor access modifiers, if any, followed by an angle-bracketed comma separated list of the 202 * constructor's type parameters, if any, followed by the fully-qualified name of the declaring class, followed by a 203 * parenthesized, comma-separated list of the constructor's generic formal parameter types. A space is used to 204 * separate access modifiers from one another and from the type parameters or return type. If there are no type 205 * parameters, the type parameter list is elided; if the type parameter list is present, a space separates the list 206 * from the class name. If the constructor is declared to throw exceptions, the parameter list is followed by a 207 * space, followed by the word "<tt>throws</tt>" followed by a comma-separated list of the thrown 208 * exception types. 209 * <p/> 210 * <p>The only possible modifiers for constructors are the access modifiers <tt>public</tt>, <tt>protected</tt> or 211 * <tt>private</tt>. Only one of these may appear, or none if the constructor has default (package) access. 212 * 213 * @return a string describing this <code>Constructor</code>, include type parameters 214 */ 215 public String toGenericString() { 216 return java.toGenericString(); 217 } 218 219 /** 220 * Uses the constructor represented by this <code>Constructor</code> object to create and initialize a new instance of 221 * the constructor's declaring class, with the specified initialization parameters. Individual parameters are 222 * automatically unwrapped to match primitive formal parameters, and both primitive and reference parameters are 223 * subject to method invocation conversions as necessary. 224 * <p/> 225 * <p>If the number of formal parameters required by the underlying constructor is 0, the supplied 226 * <code>initargs</code> array may be of length 0 or null. 227 * <p/> 228 * <p>If the required access and argument checks succeed and the instantiation will proceed, the constructor's 229 * declaring class is initialized if it has not already been initialized. 230 * <p/> 231 * <p>If the constructor completes normally, returns the newly created and initialized instance. 232 * 233 * @param initargs array of objects to be passed as arguments to the constructor call; values of primitive types are 234 * wrapped in a wrapper object of the appropriate type (e.g. a <tt>float</tt> in a {@link Float 235 * Float}) 236 * 237 * @return a new object created by calling the constructor this object represents 238 * 239 * @throws IllegalAccessException if this <code>Constructor</code> object enforces Java language access control 240 * and the underlying constructor is inaccessible. 241 * @throws IllegalArgumentException if the number of actual and formal parameters differ; if an unwrapping 242 * conversion for primitive arguments fails; or if, after possible unwrapping, a 243 * parameter value cannot be converted to the corresponding formal parameter type 244 * by a method invocation conversion; if this constructor pertains to an enum 245 * type. 246 * @throws InstantiationException if the class that declares the underlying constructor represents an abstract 247 * class. 248 * @throws java.lang.reflect.InvocationTargetException 249 * if the underlying constructor throws an exception. 250 * @throws ExceptionInInitializerError if the initialization provoked by this method fails. 251 */ 252 public T newInstance(Object[] initargs) throws InstantiationException, IllegalAccessException, 253 IllegalArgumentException, InvocationTargetException { 254 return java.newInstance(initargs); 255 } 256 257 /** 258 * Returns <tt>true</tt> if this constructor was declared to take a variable number of arguments; returns 259 * <tt>false</tt> otherwise. 260 * 261 * @return <tt>true</tt> if an only if this constructor was declared to take a variable number of arguments. 262 */ 263 public boolean isVarArgs() { 264 return java.isVarArgs(); 265 } 266 267 /** 268 * Returns <tt>true</tt> if this constructor is a synthetic constructor; returns <tt>false</tt> otherwise. 269 * 270 * @return true if and only if this constructor is a synthetic constructor as defined by the Java Language 271 * Specification. 272 */ 273 public boolean isSynthetic() { 274 return java.isSynthetic(); 275 } 276 277 278 /** 279 * Returns an array of <code>Class</code> objects that represent the formal parameter types, in declaration order, 280 * of the constructor represented by this <code>Constructor</code> object. Returns an array of length 0 if the 281 * underlying constructor takes no parameters. 282 * 283 * @return the parameter types for the constructor this object represents 284 */ 285 @SuppressWarnings("unchecked") 286 public ClassEx[] getParameterTypes() { 287 List<ClassEx> list = new ArrayList<ClassEx>(); 288 for(Class c: java.getParameterTypes()) { 289 list.add(new ClassEx(c, _classLoader)); 290 } 291 return list.toArray(new ClassEx[list.size()]); 292 293 } 294 295 /** 296 * Returns an array of arrays that represent the annotations on the formal parameters, in declaration order, of the 297 * method represented by this <tt>Method</tt> object. (Returns an array of length zero if the underlying method is 298 * parameterless. If the method has one or more parameters, a nested array of length zero is returned for each 299 * parameter with no annotations.) The annotation objects contained in the returned arrays are serializable. The 300 * caller of this method is free to modify the returned arrays; it will have no effect on the arrays returned to other 301 * callers. 302 * 303 * @return an array of arrays that represent the annotations on the formal parameters, in declaration order, of the 304 * method represented by this Method object 305 */ 306 public Annotation[][] getParameterAnnotations() { 307 Annotation[][] ann = java.getParameterAnnotations(); 308 Annotation[][] out = new Annotation[ann.length][]; 309 for(int i=0; i<ann.length; ++i) { 310 out[i] = new Annotation[ann[i].length]; 311 if (_pai!=null) { 312 for(int j=0; j<ann[i].length; ++j) { 313 out[i][j] = (Annotation)Proxy.newProxyInstance(ann[i][j].annotationType().getClassLoader(), 314 new Class[]{ann[i][j].annotationType()}, 315 new AnnotationDynamicProxyHandler(ann[i][j].annotationType(), 316 _pai.getEntityAnnotations().get(i)[j])); 317 } 318 } 319 } 320 return out; 321 } 322 323 /** 324 * Returns a map from local variable names to arrays of annotations associated with them. 325 * @return map from local variable name to arrays of annotations 326 */ 327 @SuppressWarnings("unchecked") 328 public Map<String,Annotation[]> getLocalVariableAnnotations() { 329 Map<String,Annotation[]> out = new HashMap<String,Annotation[]>(); 330 if (_lvai!=null) { 331 for(AMultipleNamedAnnotationsAttributeInfo.NamedAnnotationsRecord nar: _lvai.getEntityAnnotations()) { 332 String name = nar.getName().toString(); 333 Annotation[] arr = new Annotation[nar.getAnnotations().length]; 334 for(int i=0; i<nar.getAnnotations().length; ++i) { 335 String t = nar.getAnnotations()[i].getType().replace('/','.').replace('$', '.'); 336 // TODO: check for arrays of annotations 337 if ((t.length()==0) || (t.charAt(0)!='L')) { 338 throw new ClassFormatError("Unexpected type name for annotation: "+t); 339 } 340 t = t.substring(1,t.length()-1); 341 try { 342 Class c = Class.forName(t); 343 arr[i] = (Annotation)Proxy.newProxyInstance(c.getClassLoader(), 344 new Class[]{c}, 345 new AnnotationDynamicProxyHandler(c, 346 nar.getAnnotations()[i])); 347 } 348 catch(ClassNotFoundException e) { 349 throw new ClassFormatError("Could not find class "+t); 350 } 351 } 352 out.put(name,arr); 353 } 354 } 355 return out; 356 } 357 }