001 package edu.rice.cs.cunit.subAnnot;
002
003 import edu.rice.cs.cunit.classFile.attributes.AMultipleNamedAnnotationsAttributeInfo;
004 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleLocalVariableAnnotationsAttributeInfo;
005 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleParameterAnnotationsAttributeInfo;
006
007 import java.lang.annotation.Annotation;
008 import java.lang.reflect.*;
009 import java.util.ArrayList;
010 import java.util.HashMap;
011 import java.util.List;
012 import java.util.Map;
013
014 /**
015 * Extended Method class to support annotations with subclassing.
016 *
017 * @author Mathias Ricken
018 */
019 public class MethodEx extends AAnnotatedElementEx {
020 /**
021 * The java.lang.reflect.Method object that represents the method.
022 */
023 public final Method java;
024
025 /**
026 * Parameter annotation attribute.
027 */
028 private RuntimeVisibleParameterAnnotationsAttributeInfo _pai;
029
030 /**
031 * Local variable annotation attribute.
032 */
033 private RuntimeVisibleLocalVariableAnnotationsAttributeInfo _lvai;
034
035 /**
036 * Create an extended Method instance for the specified method.
037 * @param m method
038 */
039 public MethodEx(Method m) {
040 this(m, null);
041 }
042
043 /**
044 * Create an extended Method instance for the specified method.
045 * @param m method
046 * @param cl class loader
047 */
048 public MethodEx(Method m, ClassLoader cl) {
049 super(cl);
050 java = m;
051 findMethodAnnotationsAttributeInfo(m, m.getName(), m.getParameterTypes());
052 _pai = getParameterAnnotationsAttributeInfo(m, m.getName(), m.getParameterTypes());
053 _lvai = getLocalVarAnnotationsAttributeInfo(m, m.getName(), m.getParameterTypes());
054 }
055
056 /**
057 * Return the annotated element.
058 * @return annotated element
059 */
060 protected AnnotatedElement getAnnotatedElement() {
061 return java;
062 }
063
064 /**
065 * Returns the name of the method represented by this <code>Method</code> object, as a <code>String</code>.
066 * @return name
067 */
068 public String getName() {
069 return java.getName();
070 }
071
072 /**
073 * Returns the Java language modifiers for the method represented by this <code>Method</code> object, as an integer.
074 * The <code>Modifier</code> class should be used to decode the modifiers.
075 * @return modifiers
076 * @see java.lang.reflect.Modifier
077 */
078 public int getModifiers() {
079 return java.getModifiers();
080 }
081
082 /**
083 * Returns an array of <tt>TypeVariable</tt> objects that represent the type variables declared by the generic
084 * declaration represented by this <tt>GenericDeclaration</tt> object, in declaration order. Returns an array of
085 * length 0 if the underlying generic declaration declares no type variables.
086 *
087 * @return an array of <tt>TypeVariable</tt> objects that represent the type variables declared by this generic
088 * declaration
089 *
090 * @throws java.lang.reflect.GenericSignatureFormatError
091 * if the generic signature of this generic declaration does not conform to the format specified in the
092 * Java Virtual Machine Specification, 3rd edition
093 * @since 1.5
094 */
095 public TypeVariable<Method>[] getTypeParameters() {
096 return java.getTypeParameters();
097 }
098
099 /**
100 * Returns a <code>Class</code> object that represents the formal return type of the method represented by this
101 * <code>Method</code> object.
102 *
103 * @return the return type for the method this object represents
104 */
105 @SuppressWarnings("unchecked")
106 public ClassEx<?> getReturnType() {
107 Class<?> c = java.getReturnType();
108 return new ClassEx(c, c.getClassLoader());
109 }
110
111 /**
112 * Returns a <tt>Type</tt> object that represents the formal return type of the method represented by this
113 * <tt>Method</tt> object.
114 * <p/>
115 * <p>If the return type is a parameterized type, the <tt>Type</tt> object returned must accurately reflect the
116 * actual type parameters used in the source code.
117 * <p/>
118 * <p>If the return type is a type variable or a parameterized type, it is created. Otherwise, it is resolved.
119 *
120 * @return a <tt>Type</tt> object that represents the formal return type of the underlying method
121 *
122 * @throws java.lang.reflect.GenericSignatureFormatError
123 * if the generic method signature does not conform to the format specified in the
124 * Java Virtual Machine Specification, 3rd edition
125 * @throws TypeNotPresentException if the underlying method's return type refers to a non-existent type declaration
126 * @throws java.lang.reflect.MalformedParameterizedTypeException
127 * if the underlying method's return typed refers to a parameterized type that
128 * cannot be instantiated for any reason
129 * @since 1.5
130 */
131 public Type getGenericReturnType() {
132 return java.getGenericReturnType();
133 }
134
135 /**
136 * Returns an array of <code>Class</code> objects that represent the formal parameter types, in declaration order,
137 * of the method represented by this <code>Method</code> object. Returns an array of length 0 if the underlying
138 * method takes no parameters.
139 *
140 * @return the parameter types for the method this object represents
141 */
142 @SuppressWarnings("unchecked")
143 public ClassEx[] getParameterTypes() {
144 List<ClassEx> list = new ArrayList<ClassEx>();
145 for(Class c: java.getParameterTypes()) {
146 list.add(new ClassEx(c, c.getClassLoader()));
147 }
148 return list.toArray(new ClassEx[list.size()]);
149
150 }
151
152 /**
153 * Returns an array of <tt>Type</tt> objects that represent the formal parameter types, in declaration order, of the
154 * method represented by this <tt>Method</tt> object. Returns an array of length 0 if the underlying method takes no
155 * parameters.
156 * <p/>
157 * <p>If a formal parameter type is a parameterized type, the <tt>Type</tt> object returned for it must accurately
158 * reflect the actual type parameters used in the source code.
159 * <p/>
160 * <p>If a formal parameter type is a type variable or a parameterized type, it is created. Otherwise, it is
161 * resolved.
162 *
163 * @return an array of Types that represent the formal parameter types of the underlying method, in declaration
164 * order
165 *
166 * @throws java.lang.reflect.GenericSignatureFormatError
167 * if the generic method signature does not conform to the format specified in the
168 * Java Virtual Machine Specification, 3rd edition
169 * @throws TypeNotPresentException if any of the parameter types of the underlying method refers to a non-existent
170 * type declaration
171 * @throws java.lang.reflect.MalformedParameterizedTypeException
172 * if any of the underlying method's parameter types refer to a parameterized type
173 * that cannot be instantiated for any reason
174 * @since 1.5
175 */
176 public Type[] getGenericParameterTypes() {
177 return java.getGenericParameterTypes();
178 }
179
180 /**
181 * Returns an array of <code>Class</code> objects that represent the types of the exceptions declared to be thrown
182 * by the underlying method represented by this <code>Method</code> object. Returns an array of length 0 if the
183 * method declares no exceptions in its <code>throws</code> clause.
184 *
185 * @return the exception types declared as being thrown by the method this object represents
186 */
187 @SuppressWarnings("unchecked")
188 public ClassEx[] getExceptionTypes() {
189 List<ClassEx> list = new ArrayList<ClassEx>();
190 for(Class c: java.getExceptionTypes()) {
191 list.add(new ClassEx(c, c.getClassLoader()));
192 }
193 return list.toArray(new ClassEx[list.size()]);
194 }
195
196 /**
197 * Returns an array of <tt>Type</tt> objects that represent the exceptions declared to be thrown by this
198 * <tt>Method</tt> object. Returns an array of length 0 if the underlying method declares no exceptions in its
199 * <tt>throws</tt> clause.
200 * <p/>
201 * <p>If an exception type is a parameterized type, the <tt>Type</tt> object returned for it must accurately
202 * reflect the actual type parameters used in the source code.
203 * <p/>
204 * <p>If an exception type is a type variable or a parameterized type, it is created. Otherwise, it is resolved.
205 *
206 * @return an array of Types that represent the exception types thrown by the underlying method
207 *
208 * @throws java.lang.reflect.GenericSignatureFormatError
209 * if the generic method signature does not conform to the format specified in the
210 * Java Virtual Machine Specification, 3rd edition
211 * @throws TypeNotPresentException if the underlying method's <tt>throws</tt> clause refers to a non-existent type
212 * declaration
213 * @throws java.lang.reflect.MalformedParameterizedTypeException
214 * if the underlying method's <tt>throws</tt> clause refers to a parameterized
215 * type that cannot be instantiated for any reason
216 * @since 1.5
217 */
218 public Type[] getGenericExceptionTypes() {
219 return java.getGenericExceptionTypes();
220 }
221
222 /**
223 * Compares this <code>Method</code> against the specified object. Returns true if the objects are the same. Two
224 * <code>Methods</code> are the same if they were declared by the same class and have the same name and formal
225 * parameter types and return type.
226 */
227 public boolean equals(Object obj) {
228 return (obj!=null)&&(obj.getClass().equals(this.getClass()) && (java.equals(obj)));
229 }
230
231 /**
232 * Returns a hashcode for this <code>Method</code>. The hashcode is computed as the exclusive-or of the hashcodes
233 * for the underlying method's declaring class name and the method's name.
234 */
235 public int hashCode() {
236 return java.hashCode();
237 }
238
239 /**
240 * Returns a string describing this <code>Method</code>. The string is formatted as the method access modifiers, if
241 * any, followed by the method return type, followed by a space, followed by the class declaring the method,
242 * followed by a period, followed by the method name, followed by a parenthesized, comma-separated list of the
243 * method's formal parameter types. If the method throws checked exceptions, the parameter list is followed by a
244 * space, followed by the word throws followed by a comma-separated list of the thrown exception types. For
245 * example:
246 * <pre>
247 * public boolean java.lang.Object.equals(java.lang.Object)
248 * </pre>
249 * <p/>
250 * <p>The access modifiers are placed in canonical order as specified by "The Java Language Specification". This is
251 * <tt>public</tt>, <tt>protected</tt> or <tt>private</tt> first, and then other modifiers in the following order:
252 * <tt>abstract</tt>, <tt>static</tt>, <tt>final</tt>, <tt>synchronized</tt> <tt>native</tt>.
253 */
254 public String toString() {
255 return java.toString();
256 }
257
258 /**
259 * Returns a string describing this <code>Method</code>, including type parameters. The string is formatted as the
260 * method access modifiers, if any, followed by an angle-bracketed comma-separated list of the method's type
261 * parameters, if any, followed by the method's generic return type, followed by a space, followed by the class
262 * declaring the method, followed by a period, followed by the method name, followed by a parenthesized,
263 * comma-separated list of the method's generic formal parameter types. A space is used to separate access modifiers
264 * from one another and from the type parameters or return type. If there are no type parameters, the type
265 * parameter list is elided; if the type parameter list is present, a space separates the list from the class name.
266 * If the method is declared to throw exceptions, the parameter list is followed by a space, followed by the word
267 * throws followed by a comma-separated list of the generic thrown exception types. If there are no type parameters,
268 * the type parameter list is elided.
269 * <p/>
270 * <p>The access modifiers are placed in canonical order as specified by "The Java Language Specification". This is
271 * <tt>public</tt>, <tt>protected</tt> or <tt>private</tt> first, and then other modifiers in the following order:
272 * <tt>abstract</tt>, <tt>static</tt>, <tt>final</tt>, <tt>synchronized</tt> <tt>native</tt>.
273 *
274 * @return a string describing this <code>Method</code>, include type parameters
275 *
276 * @since 1.5
277 */
278 public String toGenericString() {
279 return java.toGenericString();
280 }
281
282 /**
283 * Invokes the underlying method represented by this <code>Method</code> object, on the specified object with the
284 * specified parameters. Individual parameters are automatically unwrapped to match primitive formal parameters, and
285 * both primitive and reference parameters are subject to method invocation conversions as necessary.
286 * <p/>
287 * <p>If the underlying method is static, then the specified <code>obj</code> argument is ignored. It may be null.
288 * <p/>
289 * <p>If the number of formal parameters required by the underlying method is 0, the supplied <code>args</code>
290 * array may be of length 0 or null.
291 * <p/>
292 * <p>If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The
293 * Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime
294 * type of the target object will occur.
295 * <p/>
296 * <p>If the underlying method is static, the class that declared the method is initialized if it has not already
297 * been initialized.
298 * <p/>
299 * <p>If the method completes normally, the value it returns is returned to the caller of invoke; if the value has a
300 * primitive type, it is first appropriately wrapped in an object. However, if the value has the type of an array of
301 * a primitive type, the elements of the array are <i>not</i> wrapped in objects; in other words, an array of
302 * primitive type is returned. If the underlying method return type is void, the invocation returns null.
303 *
304 * @param obj the object the underlying method is invoked from
305 * @param args the arguments used for the method call
306 *
307 * @return the result of dispatching the method represented by this object on <code>obj</code> with parameters
308 * <code>args</code>
309 *
310 * @throws IllegalAccessException if this <code>Method</code> object enforces Java language access control and
311 * the underlying method is inaccessible.
312 * @throws IllegalArgumentException if the method is an instance method and the specified object argument is not
313 * an instance of the class or interface declaring the underlying method (or of
314 * a subclass or implementor thereof); if the number of actual and formal
315 * parameters differ; if an unwrapping conversion for primitive arguments fails;
316 * or if, after possible unwrapping, a parameter value cannot be converted to
317 * the corresponding formal parameter type by a method invocation conversion.
318 * @throws java.lang.reflect.InvocationTargetException
319 * if the underlying method throws an exception.
320 * @throws NullPointerException if the specified object is null and the method is an instance method.
321 * @throws ExceptionInInitializerError if the initialization provoked by this method fails.
322 */
323 public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,
324 InvocationTargetException {
325 return java.invoke(obj, args);
326 }
327
328 /**
329 * Returns <tt>true</tt> if this method is a bridge method; returns <tt>false</tt> otherwise.
330 *
331 * @return true if and only if this method is a bridge method as defined by the Java Language Specification.
332 *
333 * @since 1.5
334 */
335 public boolean isBridge() {
336 return java.isBridge();
337 }
338
339 /**
340 * Returns <tt>true</tt> if this method was declared to take a variable number of arguments; returns <tt>false</tt>
341 * otherwise.
342 *
343 * @return <tt>true</tt> if an only if this method was declared to take a variable number of arguments.
344 *
345 * @since 1.5
346 */
347 public boolean isVarArgs() {
348 return java.isVarArgs();
349 }
350
351 /**
352 * Returns <tt>true</tt> if this method is a synthetic method; returns <tt>false</tt> otherwise.
353 *
354 * @return true if and only if this method is a synthetic method as defined by the Java Language Specification.
355 *
356 * @since 1.5
357 */
358 public boolean isSynthetic() {
359 return java.isSynthetic();
360 }
361
362 /**
363 * Returns the default value for the annotation member represented by this <tt>Method</tt> instance. If the member
364 * is of a primitive type, an instance of the corresponding wrapper type is returned. Returns null if no default is
365 * associated with the member, or if the method instance does not represent a declared member of an annotation
366 * type.
367 *
368 * @return the default value for the annotation member represented by this <tt>Method</tt> instance.
369 *
370 * @throws TypeNotPresentException if the annotation is of type {@link Class} and no definition can be found for the
371 * default class value.
372 * @since 1.5
373 */
374 public Object getDefaultValue() {
375 return java.getDefaultValue();
376 }
377
378 /**
379 * Returns an array of arrays that represent the annotations on the formal parameters, in declaration order, of the
380 * method represented by this <tt>Method</tt> object. (Returns an array of length zero if the underlying method is
381 * parameterless. If the method has one or more parameters, a nested array of length zero is returned for each
382 * parameter with no annotations.) The annotation objects contained in the returned arrays are serializable. The
383 * caller of this method is free to modify the returned arrays; it will have no effect on the arrays returned to
384 * other callers.
385 *
386 * @return an array of arrays that represent the annotations on the formal parameters, in declaration order, of the
387 * method represented by this Method object
388 *
389 * @since 1.5
390 */
391 public Annotation[][] getParameterAnnotations() {
392 Annotation[][] ann = java.getParameterAnnotations();
393 Annotation[][] out = new Annotation[ann.length][];
394 for(int i=0; i<ann.length; ++i) {
395 out[i] = new Annotation[ann[i].length];
396 if (_pai!=null) {
397 for(int j=0; j<ann[i].length; ++j) {
398 out[i][j] = (Annotation)Proxy.newProxyInstance(ann[i][j].annotationType().getClassLoader(),
399 new Class[]{ann[i][j].annotationType()},
400 new AnnotationDynamicProxyHandler(ann[i][j].annotationType(),
401 _pai.getEntityAnnotations().get(i)[j]));
402 }
403 }
404 }
405 return out;
406 }
407
408 /**
409 * Returns a map from local variable names to arrays of annotations associated with them.
410 * @return map from local variable name to arrays of annotations
411 */
412 @SuppressWarnings("unchecked")
413 public Map<String,Annotation[]> getLocalVariableAnnotations() {
414 Map<String,Annotation[]> out = new HashMap<String,Annotation[]>();
415 if (_lvai!=null) {
416 for(AMultipleNamedAnnotationsAttributeInfo.NamedAnnotationsRecord nar: _lvai.getEntityAnnotations()) {
417 String name = nar.getName().toString();
418 Annotation[] arr = new Annotation[nar.getAnnotations().length];
419 for(int i=0; i<nar.getAnnotations().length; ++i) {
420 String t = nar.getAnnotations()[i].getType().replace('/','.').replace('$', '.');
421 // TODO: check for arrays of annotations
422 if ((t.length()==0) || (t.charAt(0)!='L')) {
423 throw new ClassFormatError("Unexpected type name for annotation: "+t);
424 }
425 t = t.substring(1,t.length()-1);
426 try {
427 Class c = Class.forName(t);
428 arr[i] = (Annotation)Proxy.newProxyInstance(c.getClassLoader(),
429 new Class[]{c},
430 new AnnotationDynamicProxyHandler(c,
431 nar.getAnnotations()[i]));
432 }
433 catch(ClassNotFoundException e) {
434 throw new ClassFormatError("Could not find class "+t);
435 }
436 }
437 out.put(name,arr);
438 }
439 }
440 return out;
441 }
442 }