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