• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /*
18  * Copyright (C) 2008 The Android Open Source Project
19  *
20  * Licensed under the Apache License, Version 2.0 (the "License");
21  * you may not use this file except in compliance with the License.
22  * You may obtain a copy of the License at
23  *
24  *      http://www.apache.org/licenses/LICENSE-2.0
25  *
26  * Unless required by applicable law or agreed to in writing, software
27  * distributed under the License is distributed on an "AS IS" BASIS,
28  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29  * See the License for the specific language governing permissions and
30  * limitations under the License.
31  */
32 
33 package java.lang.reflect;
34 
35 import java.lang.annotation.Annotation;
36 import java.util.Comparator;
37 import libcore.util.EmptyArray;
38 import org.apache.harmony.kernel.vm.StringUtils;
39 import org.apache.harmony.luni.lang.reflect.GenericSignatureParser;
40 import org.apache.harmony.luni.lang.reflect.ListOfTypes;
41 import org.apache.harmony.luni.lang.reflect.Types;
42 
43 /**
44  * This class represents a method. Information about the method can be accessed,
45  * and the method can be invoked dynamically.
46  */
47 public final class Method extends AccessibleObject implements GenericDeclaration, Member {
48 
49     /**
50      * Orders methods by their name, parameters and return type.
51      *
52      * @hide
53      */
54     public static final Comparator<Method> ORDER_BY_SIGNATURE = new Comparator<Method>() {
55         public int compare(Method a, Method b) {
56             int comparison = a.name.compareTo(b.name);
57             if (comparison != 0) {
58                 return comparison;
59             }
60 
61             Class<?>[] aParameters = a.parameterTypes;
62             Class<?>[] bParameters = b.parameterTypes;
63             int length = Math.min(aParameters.length, bParameters.length);
64             for (int i = 0; i < length; i++) {
65                 comparison = aParameters[i].getName().compareTo(bParameters[i].getName());
66                 if (comparison != 0) {
67                     return comparison;
68                 }
69             }
70 
71             if (aParameters.length != bParameters.length) {
72                 return aParameters.length - bParameters.length;
73             }
74 
75             // this is necessary for methods that have covariant return types.
76             return a.getReturnType().getName().compareTo(b.getReturnType().getName());
77         }
78     };
79 
80     private int slot;
81 
82     private Class<?> declaringClass;
83 
84     private String name;
85 
86     private Class<?>[] parameterTypes;
87 
88     private Class<?>[] exceptionTypes;
89 
90     private Class<?> returnType;
91 
92     private ListOfTypes genericExceptionTypes;
93     private ListOfTypes genericParameterTypes;
94     private Type genericReturnType;
95     private TypeVariable<Method>[] formalTypeParameters;
96     private volatile boolean genericTypesAreInitialized = false;
97 
initGenericTypes()98     private synchronized void initGenericTypes() {
99         if (!genericTypesAreInitialized) {
100             String signatureAttribute = getSignatureAttribute();
101             GenericSignatureParser parser = new GenericSignatureParser(
102                     declaringClass.getClassLoader());
103             parser.parseForMethod(this, signatureAttribute, exceptionTypes);
104             formalTypeParameters = parser.formalTypeParameters;
105             genericParameterTypes = parser.parameterTypes;
106             genericExceptionTypes = parser.exceptionTypes;
107             genericReturnType = parser.returnType;
108             genericTypesAreInitialized = true;
109         }
110     }
111 
112     /**
113      * Construct a clone of the given instance.
114      *
115      * @param orig non-null; the original instance to clone
116      */
Method(Method orig)117     /*package*/ Method(Method orig) {
118         this(orig.declaringClass, orig.parameterTypes, orig.exceptionTypes,
119                 orig.returnType, orig.name, orig.slot);
120 
121         // Copy the accessible flag.
122         if (orig.flag) {
123             this.flag = true;
124         }
125     }
126 
Method(Class<?> declaring, Class<?>[] paramTypes, Class<?>[] exceptTypes, Class<?> returnType, String name, int slot)127     private Method(Class<?> declaring, Class<?>[] paramTypes, Class<?>[] exceptTypes, Class<?> returnType, String name, int slot)
128     {
129         this.declaringClass = declaring;
130         this.name = name;
131         this.slot = slot;
132         this.parameterTypes = paramTypes;
133         this.exceptionTypes = exceptTypes;      // may be null
134         this.returnType = returnType;
135     }
136 
getTypeParameters()137     public TypeVariable<Method>[] getTypeParameters() {
138         initGenericTypes();
139         return formalTypeParameters.clone();
140     }
141 
142     /** {@inheritDoc} */
getSignatureAttribute()143     @Override /*package*/ String getSignatureAttribute() {
144         Object[] annotation = getSignatureAnnotation(declaringClass, slot);
145 
146         if (annotation == null) {
147             return null;
148         }
149 
150         return StringUtils.combineStrings(annotation);
151     }
152 
153     /**
154      * Returns the Signature annotation for this method. Returns {@code null} if
155      * not found.
156      */
getSignatureAnnotation(Class declaringClass, int slot)157     static native Object[] getSignatureAnnotation(Class declaringClass, int slot);
158 
159     /**
160      * Returns the string representation of the method's declaration, including
161      * the type parameters.
162      *
163      * @return the string representation of this method
164      */
toGenericString()165     public String toGenericString() {
166         StringBuilder sb = new StringBuilder(80);
167 
168         initGenericTypes();
169 
170         // append modifiers if any
171         int modifier = getModifiers();
172         if (modifier != 0) {
173             sb.append(Modifier.toString(modifier & ~(Modifier.BRIDGE +
174                     Modifier.VARARGS))).append(' ');
175         }
176         // append type parameters
177         if (formalTypeParameters != null && formalTypeParameters.length > 0) {
178             sb.append('<');
179             for (int i = 0; i < formalTypeParameters.length; i++) {
180                 appendGenericType(sb, formalTypeParameters[i]);
181                 if (i < formalTypeParameters.length - 1) {
182                     sb.append(",");
183                 }
184             }
185             sb.append("> ");
186         }
187         // append return type
188         appendGenericType(sb, Types.getType(genericReturnType));
189         sb.append(' ');
190         // append method name
191         appendTypeName(sb, getDeclaringClass());
192         sb.append(".").append(getName());
193         // append parameters
194         sb.append('(');
195         appendArrayGenericType(sb,
196                 Types.getClonedTypeArray(genericParameterTypes));
197         sb.append(')');
198         // append exceptions if any
199         Type[] genericExceptionTypeArray = Types.getClonedTypeArray(
200                 genericExceptionTypes);
201         if (genericExceptionTypeArray.length > 0) {
202             sb.append(" throws ");
203             appendArrayGenericType(sb, genericExceptionTypeArray);
204         }
205         return sb.toString();
206     }
207 
208     /**
209      * Returns the parameter types as an array of {@code Type} instances, in
210      * declaration order. If this method has no parameters, an empty array is
211      * returned.
212      *
213      * @return the parameter types
214      *
215      * @throws GenericSignatureFormatError
216      *             if the generic method signature is invalid
217      * @throws TypeNotPresentException
218      *             if any parameter type points to a missing type
219      * @throws MalformedParameterizedTypeException
220      *             if any parameter type points to a type that cannot be
221      *             instantiated for some reason
222      */
getGenericParameterTypes()223     public Type[] getGenericParameterTypes() {
224         initGenericTypes();
225         return Types.getClonedTypeArray(genericParameterTypes);
226     }
227 
228     /**
229      * Returns the exception types as an array of {@code Type} instances. If
230      * this method has no declared exceptions, an empty array will be returned.
231      *
232      * @return an array of generic exception types
233      *
234      * @throws GenericSignatureFormatError
235      *             if the generic method signature is invalid
236      * @throws TypeNotPresentException
237      *             if any exception type points to a missing type
238      * @throws MalformedParameterizedTypeException
239      *             if any exception type points to a type that cannot be
240      *             instantiated for some reason
241      */
getGenericExceptionTypes()242     public Type[] getGenericExceptionTypes() {
243         initGenericTypes();
244         return Types.getClonedTypeArray(genericExceptionTypes);
245     }
246 
247     /**
248      * Returns the return type of this method as a {@code Type} instance.
249      *
250      * @return the return type of this method
251      *
252      * @throws GenericSignatureFormatError
253      *             if the generic method signature is invalid
254      * @throws TypeNotPresentException
255      *             if the return type points to a missing type
256      * @throws MalformedParameterizedTypeException
257      *             if the return type points to a type that cannot be
258      *             instantiated for some reason
259      */
getGenericReturnType()260     public Type getGenericReturnType() {
261         initGenericTypes();
262         return Types.getType(genericReturnType);
263     }
264 
265     @Override
getDeclaredAnnotations()266     public Annotation[] getDeclaredAnnotations() {
267         return getDeclaredAnnotations(declaringClass, slot);
268     }
getDeclaredAnnotations(Class<?> declaringClass, int slot)269     static native Annotation[] getDeclaredAnnotations(Class<?> declaringClass, int slot);
270 
getAnnotation(Class<A> annotationType)271     @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
272         if (annotationType == null) {
273             throw new NullPointerException("annotationType == null");
274         }
275         return getAnnotation(declaringClass, slot, annotationType);
276     }
getAnnotation( Class<?> declaringClass, int slot, Class<A> annotationType)277     static native <A extends Annotation> A getAnnotation(
278             Class<?> declaringClass, int slot, Class<A> annotationType);
279 
isAnnotationPresent(Class<? extends Annotation> annotationType)280     @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
281         if (annotationType == null) {
282             throw new NullPointerException("annotationType == null");
283         }
284         return isAnnotationPresent(declaringClass, slot, annotationType);
285     }
isAnnotationPresent( Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType)286     static native boolean isAnnotationPresent(
287             Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType);
288 
289     private static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
290 
291     /**
292      * Creates an array of empty Annotation arrays.
293      */
noAnnotations(int size)294     /*package*/ static Annotation[][] noAnnotations(int size) {
295         Annotation[][] annotations = new Annotation[size][];
296         for (int i = 0; i < size; i++) {
297             annotations[i] = NO_ANNOTATIONS;
298         }
299         return annotations;
300     }
301 
302     /**
303      * Returns an array of arrays that represent the annotations of the formal
304      * parameters of this method. If there are no parameters on this method,
305      * then an empty array is returned. If there are no annotations set, then
306      * and array of empty arrays is returned.
307      *
308      * @return an array of arrays of {@code Annotation} instances
309      */
getParameterAnnotations()310     public Annotation[][] getParameterAnnotations() {
311         Annotation[][] parameterAnnotations
312                 = getParameterAnnotations(declaringClass, slot);
313         if (parameterAnnotations.length == 0) {
314             return noAnnotations(parameterTypes.length);
315         }
316         return parameterAnnotations;
317     }
318 
getParameterAnnotations(Class declaringClass, int slot)319     static native Annotation[][] getParameterAnnotations(Class declaringClass, int slot);
320 
321     /**
322      * Indicates whether or not this method takes a variable number argument.
323      *
324      * @return {@code true} if a vararg is declared, {@code false} otherwise
325      */
isVarArgs()326     public boolean isVarArgs() {
327         int modifiers = getMethodModifiers(declaringClass, slot);
328         return (modifiers & Modifier.VARARGS) != 0;
329     }
330 
331     /**
332      * Indicates whether or not this method is a bridge.
333      *
334      * @return {@code true} if this method is a bridge, {@code false} otherwise
335      */
isBridge()336     public boolean isBridge() {
337         int modifiers = getMethodModifiers(declaringClass, slot);
338         return (modifiers & Modifier.BRIDGE) != 0;
339     }
340 
341     /**
342      * Indicates whether or not this method is synthetic.
343      *
344      * @return {@code true} if this method is synthetic, {@code false} otherwise
345      */
isSynthetic()346     public boolean isSynthetic() {
347         int modifiers = getMethodModifiers(declaringClass, slot);
348         return (modifiers & Modifier.SYNTHETIC) != 0;
349     }
350 
351     /**
352      * Returns the default value for the annotation member represented by this
353      * method.
354      *
355      * @return the default value, or {@code null} if none
356      *
357      * @throws TypeNotPresentException
358      *             if this annotation member is of type {@code Class} and no
359      *             definition can be found
360      */
getDefaultValue()361     public Object getDefaultValue() {
362         return getDefaultValue(declaringClass, slot);
363     }
getDefaultValue(Class declaringClass, int slot)364     native private Object getDefaultValue(Class declaringClass, int slot);
365 
366     /**
367      * Indicates whether or not the specified {@code object} is equal to this
368      * method. To be equal, the specified object must be an instance
369      * of {@code Method} with the same declaring class and parameter types
370      * as this method.
371      *
372      * @param object
373      *            the object to compare
374      *
375      * @return {@code true} if the specified object is equal to this
376      *         method, {@code false} otherwise
377      *
378      * @see #hashCode
379      */
380     @Override
equals(Object object)381     public boolean equals(Object object) {
382         return object instanceof Method && toString().equals(object.toString());
383     }
384 
385     /**
386      * Returns the class that declares this method.
387      *
388      * @return the declaring class
389      */
getDeclaringClass()390     public Class<?> getDeclaringClass() {
391         return declaringClass;
392     }
393 
394     /**
395      * Returns the exception types as an array of {@code Class} instances. If
396      * this method has no declared exceptions, an empty array is returned.
397      *
398      * @return the declared exception classes
399      */
getExceptionTypes()400     public Class<?>[] getExceptionTypes() {
401         if (exceptionTypes == null) {
402             return EmptyArray.CLASS;
403         }
404         return exceptionTypes.clone();
405     }
406 
407     /**
408      * Returns the modifiers for this method. The {@link Modifier} class should
409      * be used to decode the result.
410      *
411      * @return the modifiers for this method
412      *
413      * @see Modifier
414      */
getModifiers()415     public int getModifiers() {
416         return getMethodModifiers(declaringClass, slot);
417     }
418 
getMethodModifiers(Class<?> declaringClass, int slot)419     static native int getMethodModifiers(Class<?> declaringClass, int slot);
420 
421     /**
422      * Returns the name of the method represented by this {@code Method}
423      * instance.
424      *
425      * @return the name of this method
426      */
getName()427     public String getName() {
428         return name;
429     }
430 
431     /**
432      * Returns an array of {@code Class} objects associated with the parameter
433      * types of this method. If the method was declared with no parameters, an
434      * empty array will be returned.
435      *
436      * @return the parameter types
437      */
getParameterTypes()438     public Class<?>[] getParameterTypes() {
439         return parameterTypes.clone();
440     }
441 
442     /**
443      * Returns the {@code Class} associated with the return type of this
444      * method.
445      *
446      * @return the return type
447      */
getReturnType()448     public Class<?> getReturnType() {
449         return returnType;
450     }
451 
452     /**
453      * Returns an integer hash code for this method. Objects which are equal
454      * return the same value for this method. The hash code for this Method is
455      * the hash code of the name of this method.
456      *
457      * @return hash code for this method
458      *
459      * @see #equals
460      */
461     @Override
hashCode()462     public int hashCode() {
463         return name.hashCode();
464     }
465 
466     /**
467      * Returns the result of dynamically invoking this method. Equivalent to
468      * {@code receiver.methodName(arg1, arg2, ... , argN)}.
469      *
470      * <p>If the method is static, the receiver argument is ignored (and may be null).
471      *
472      * <p>If the method takes no arguments, you can pass {@code (Object[]) null} instead of
473      * allocating an empty array.
474      *
475      * <p>If you're calling a varargs method, you need to pass an {@code Object[]} for the
476      * varargs parameter: that conversion is usually done in {@code javac}, not the VM, and
477      * the reflection machinery does not do this for you. (It couldn't, because it would be
478      * ambiguous.)
479      *
480      * <p>Reflective method invocation follows the usual process for method lookup.
481      *
482      * <p>If an exception is thrown during the invocation it is caught and
483      * wrapped in an InvocationTargetException. This exception is then thrown.
484      *
485      * <p>If the invocation completes normally, the return value itself is
486      * returned. If the method is declared to return a primitive type, the
487      * return value is boxed. If the return type is void, null is returned.
488      *
489      * @param receiver
490      *            the object on which to call this method (or null for static methods)
491      * @param args
492      *            the arguments to the method
493      * @return the result
494      *
495      * @throws NullPointerException
496      *             if {@code receiver == null} for a non-static method
497      * @throws IllegalAccessException
498      *             if this method is not accessible (see {@link AccessibleObject})
499      * @throws IllegalArgumentException
500      *             if the number of arguments doesn't match the number of parameters, the receiver
501      *             is incompatible with the declaring class, or an argument could not be unboxed
502      *             or converted by a widening conversion to the corresponding parameter type
503      * @throws InvocationTargetException
504      *             if an exception was thrown by the invoked method
505      */
invoke(Object receiver, Object... args)506     public Object invoke(Object receiver, Object... args)
507             throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
508         if (args == null) {
509             args = EmptyArray.OBJECT;
510         }
511         return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);
512     }
513 
invokeNative(Object obj, Object[] args, Class<?> declaringClass, Class<?>[] parameterTypes, Class<?> returnType, int slot, boolean noAccessCheck)514     private native Object invokeNative(Object obj, Object[] args, Class<?> declaringClass,
515             Class<?>[] parameterTypes, Class<?> returnType, int slot, boolean noAccessCheck)
516                     throws IllegalAccessException, IllegalArgumentException,
517                             InvocationTargetException;
518 
519     /**
520      * Returns a string containing a concise, human-readable description of this
521      * method. The format of the string is:
522      *
523      * <ol>
524      *   <li>modifiers (if any)
525      *   <li>return type or 'void'
526      *   <li>declaring class name
527      *   <li>'('
528      *   <li>parameter types, separated by ',' (if any)
529      *   <li>')'
530      *   <li>'throws' plus exception types, separated by ',' (if any)
531      * </ol>
532      *
533      * For example: {@code public native Object
534      * java.lang.Method.invoke(Object,Object) throws
535      * IllegalAccessException,IllegalArgumentException
536      * ,InvocationTargetException}
537      *
538      * @return a printable representation for this method
539      */
540     @Override
toString()541     public String toString() {
542         StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
543 
544         if (result.length() != 0)
545             result.append(' ');
546         result.append(returnType.getName());
547         result.append(' ');
548         result.append(declaringClass.getName());
549         result.append('.');
550         result.append(name);
551         result.append("(");
552         result.append(toString(parameterTypes));
553         result.append(")");
554         if (exceptionTypes != null && exceptionTypes.length != 0) {
555             result.append(" throws ");
556             result.append(toString(exceptionTypes));
557         }
558 
559         return result.toString();
560     }
561 
562     /**
563      * Returns the constructor's signature in non-printable form. This is called
564      * (only) from IO native code and needed for deriving the serialVersionUID
565      * of the class
566      *
567      * @return The constructor's signature.
568      */
569     @SuppressWarnings("unused")
getSignature()570     private String getSignature() {
571         StringBuilder result = new StringBuilder();
572 
573         result.append('(');
574         for (int i = 0; i < parameterTypes.length; i++) {
575             result.append(getSignature(parameterTypes[i]));
576         }
577         result.append(')');
578         result.append(getSignature(returnType));
579 
580         return result.toString();
581     }
582 
583 }
584