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