1 /*
2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.lang.reflect;
26 
27 import dalvik.annotation.optimization.FastNative;
28 import java.lang.annotation.*;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Objects;
32 import libcore.reflect.AnnotatedElements;
33 
34 /**
35  * Information about method parameters.
36  *
37  * A {@code Parameter} provides information about method parameters,
38  * including its name and modifiers.  It also provides an alternate
39  * means of obtaining attributes for the parameter.
40  *
41  * @since 1.8
42  */
43 public final class Parameter implements AnnotatedElement {
44     // Android-changed: Extensive modifications made throughout the class for ART.
45     // Android-removed: Type annotations runtime code. Not supported on Android.
46     // Android-removed: Annotation retrieval is implemented natively in ART.
47 
48     private final String name;
49     private final int modifiers;
50     private final Executable executable;
51     private final int index;
52 
53     /**
54      * Package-private constructor for {@code Parameter}.
55      *
56      * If method parameter data is present in the classfile, then the
57      * JVM creates {@code Parameter} objects directly.  If it is
58      * absent, however, then {@code Executable} uses this constructor
59      * to synthesize them.
60      *
61      * @param name The name of the parameter.
62      * @param modifiers The modifier flags for the parameter.
63      * @param executable The executable which defines this parameter.
64      * @param index The index of the parameter.
65      */
Parameter(String name, int modifiers, Executable executable, int index)66     Parameter(String name,
67               int modifiers,
68               Executable executable,
69               int index) {
70         this.name = name;
71         this.modifiers = modifiers;
72         this.executable = executable;
73         this.index = index;
74     }
75 
76     /**
77      * Compares based on the executable and the index.
78      *
79      * @param obj The object to compare.
80      * @return Whether or not this is equal to the argument.
81      */
equals(Object obj)82     public boolean equals(Object obj) {
83         if(obj instanceof Parameter) {
84             Parameter other = (Parameter)obj;
85             return (other.executable.equals(executable) &&
86                     other.index == index);
87         }
88         return false;
89     }
90 
91     /**
92      * Returns a hash code based on the executable's hash code and the
93      * index.
94      *
95      * @return A hash code based on the executable's hash code.
96      */
hashCode()97     public int hashCode() {
98         return executable.hashCode() ^ index;
99     }
100 
101     // Android-changed: Removed references in javadoc to the class file format.
102     /**
103      * Returns true if the parameter has a name; returns false otherwise.
104      * Whether a parameter has a name is determined by compiler options
105      * and whether the parameter is synthesized.
106      *
107      * @return true if and only if the parameter has a name
108      */
isNamePresent()109     public boolean isNamePresent() {
110         return executable.hasRealParameterData() && name != null;
111     }
112 
113     /**
114      * Returns a string describing this parameter.  The format is the
115      * modifiers for the parameter, if any, in canonical order as
116      * recommended by <cite>The Java&trade; Language
117      * Specification</cite>, followed by the fully- qualified type of
118      * the parameter (excluding the last [] if the parameter is
119      * variable arity), followed by "..." if the parameter is variable
120      * arity, followed by a space, followed by the name of the
121      * parameter.
122      *
123      * @return A string representation of the parameter and associated
124      * information.
125      */
toString()126     public String toString() {
127         final StringBuilder sb = new StringBuilder();
128         final Type type = getParameterizedType();
129         final String typename = type.getTypeName();
130 
131         sb.append(Modifier.toString(getModifiers()));
132 
133         if(0 != modifiers)
134             sb.append(' ');
135 
136         if(isVarArgs())
137             sb.append(typename.replaceFirst("\\[\\]$", "..."));
138         else
139             sb.append(typename);
140 
141         sb.append(' ');
142         sb.append(getName());
143 
144         return sb.toString();
145     }
146 
147     /**
148      * Return the {@code Executable} which declares this parameter.
149      *
150      * @return The {@code Executable} declaring this parameter.
151      */
getDeclaringExecutable()152     public Executable getDeclaringExecutable() {
153         return executable;
154     }
155 
156     /**
157      * Get the modifier flags for this the parameter represented by
158      * this {@code Parameter} object.
159      *
160      * @return The modifier flags for this parameter.
161      */
getModifiers()162     public int getModifiers() {
163         return modifiers;
164     }
165 
166     /**
167      * Returns the name of the parameter.  If the parameter's name is
168      * {@linkplain #isNamePresent() present}, then this method returns
169      * the name provided by the class file. Otherwise, this method
170      * synthesizes a name of the form argN, where N is the index of
171      * the parameter in the descriptor of the method which declares
172      * the parameter.
173      *
174      * @return The name of the parameter, either provided by the class
175      *         file or synthesized if the class file does not provide
176      *         a name.
177      */
getName()178     public String getName() {
179         // Note: empty strings as parameter names are now outlawed.
180         // The .equals("") is for compatibility with current JVM
181         // behavior.  It may be removed at some point.
182         if(name == null || name.equals(""))
183             return "arg" + index;
184         else
185             return name;
186     }
187 
188     // Package-private accessor to the real name field.
getRealName()189     String getRealName() {
190         return name;
191     }
192 
193     /**
194      * Returns a {@code Type} object that identifies the parameterized
195      * type for the parameter represented by this {@code Parameter}
196      * object.
197      *
198      * @return a {@code Type} object identifying the parameterized
199      * type of the parameter represented by this object
200      */
getParameterizedType()201     public Type getParameterizedType() {
202         Type tmp = parameterTypeCache;
203         if (null == tmp) {
204             tmp = executable.getAllGenericParameterTypes()[index];
205             parameterTypeCache = tmp;
206         }
207 
208         return tmp;
209     }
210 
211     private transient volatile Type parameterTypeCache;
212 
213     /**
214      * Returns a {@code Class} object that identifies the
215      * declared type for the parameter represented by this
216      * {@code Parameter} object.
217      *
218      * @return a {@code Class} object identifying the declared
219      * type of the parameter represented by this object
220      */
getType()221     public Class<?> getType() {
222         Class<?> tmp = parameterClassCache;
223         if (null == tmp) {
224             tmp = executable.getParameterTypes()[index];
225             parameterClassCache = tmp;
226         }
227         return tmp;
228     }
229 
230     private transient volatile Class<?> parameterClassCache = null;
231 
232     /**
233      * Returns {@code true} if this parameter is implicitly declared
234      * in source code; returns {@code false} otherwise.
235      *
236      * @return true if and only if this parameter is implicitly
237      * declared as defined by <cite>The Java&trade; Language
238      * Specification</cite>.
239      */
isImplicit()240     public boolean isImplicit() {
241         return Modifier.isMandated(getModifiers());
242     }
243 
244     /**
245      * Returns {@code true} if this parameter is neither implicitly
246      * nor explicitly declared in source code; returns {@code false}
247      * otherwise.
248      *
249      * @jls 13.1 The Form of a Binary
250      * @return true if and only if this parameter is a synthetic
251      * construct as defined by
252      * <cite>The Java&trade; Language Specification</cite>.
253      */
isSynthetic()254     public boolean isSynthetic() {
255         return Modifier.isSynthetic(getModifiers());
256     }
257 
258     /**
259      * Returns {@code true} if this parameter represents a variable
260      * argument list; returns {@code false} otherwise.
261      *
262      * @return {@code true} if an only if this parameter represents a
263      * variable argument list.
264      */
isVarArgs()265     public boolean isVarArgs() {
266         return executable.isVarArgs() &&
267             index == executable.getParameterCount() - 1;
268     }
269 
270 
271     /**
272      * {@inheritDoc}
273      * @throws NullPointerException {@inheritDoc}
274      */
getAnnotation(Class<T> annotationClass)275     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
276         Objects.requireNonNull(annotationClass);
277         // Android-changed: getAnnotation(Class) Uses native code to obtain annotation information.
278         return getAnnotationNative(executable, index, annotationClass);
279     }
280     // Android-added: getAnnotation(Class) Uses native code to obtain annotation information.
281     @FastNative
getAnnotationNative( Executable executable, int parameterIndex, Class<A> annotationType)282     private static native <A extends Annotation> A getAnnotationNative(
283             Executable executable, int parameterIndex, Class<A> annotationType);
284 
285     /**
286      * {@inheritDoc}
287      * @throws NullPointerException {@inheritDoc}
288      */
289     @Override
getAnnotationsByType(Class<T> annotationClass)290     public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
291         // Android-changed: getAnnotationsByType(Class), Android uses AnnotatedElements instead.
292         return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
293     }
294 
295     /**
296      * {@inheritDoc}
297      */
getDeclaredAnnotations()298     public Annotation[] getDeclaredAnnotations() {
299         return executable.getParameterAnnotations()[index];
300     }
301 
302     /**
303      * @throws NullPointerException {@inheritDoc}
304      */
getDeclaredAnnotation(Class<T> annotationClass)305     public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
306         // Only annotations on classes are inherited, for all other
307         // objects getDeclaredAnnotation is the same as
308         // getAnnotation.
309         return getAnnotation(annotationClass);
310     }
311 
312     /**
313      * @throws NullPointerException {@inheritDoc}
314      */
315     @Override
getDeclaredAnnotationsByType(Class<T> annotationClass)316     public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
317         // Only annotations on classes are inherited, for all other
318         // objects getDeclaredAnnotations is the same as
319         // getAnnotations.
320         return getAnnotationsByType(annotationClass);
321     }
322 
323     /**
324      * {@inheritDoc}
325      */
getAnnotations()326     public Annotation[] getAnnotations() {
327         return getDeclaredAnnotations();
328     }
329 
330 }
331