1 /*
  2  * Copyright (c) 2013, 2021, 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 java.lang.annotation.*;
 28 import java.util.HashMap;
 29 import java.util.Map;
 30 import java.util.Set;
 31 import java.util.Objects;
 32 import sun.reflect.annotation.AnnotationSupport;
 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 
 45     private final String name;
 46     private final int modifiers;
 47     private final Executable executable;
 48     private final int index;
 49 
 50     /**
 51      * Package-private constructor for {@code Parameter}.
 52      *
 53      * If method parameter data is present in the classfile, then the
 54      * JVM creates {@code Parameter} objects directly.  If it is
 55      * absent, however, then {@code Executable} uses this constructor
 56      * to synthesize them.
 57      *
 58      * @param name The name of the parameter.
 59      * @param modifiers The modifier flags for the parameter.
 60      * @param executable The executable which defines this parameter.
 61      * @param index The index of the parameter.
 62      */
 63     Parameter(String name,
 64               int modifiers,
 65               Executable executable,
 66               int index) {
 67         this.name = name;
 68         this.modifiers = modifiers;
 69         this.executable = executable;
 70         this.index = index;
 71     }
 72 
 73     /**
 74      * Compares based on the executable and the index.
 75      *
 76      * @param obj The object to compare.
 77      * @return Whether or not this is equal to the argument.
 78      */
 79     @Override
 80     public boolean equals(Object obj) {
 81         return (obj instanceof Parameter other)
 82                 && other.executable.equals(executable)
 83                 && other.index == index;
 84     }
 85 
 86     /**
 87      * Returns a hash code based on the executable's hash code and the
 88      * index.
 89      *
 90      * @return A hash code based on the executable's hash code.
 91      */
 92     @Override
 93     public int hashCode() {
 94         return executable.hashCode() ^ index;
 95     }
 96 
 97     /**
 98      * Returns true if the parameter has a name according to the class
 99      * file; returns false otherwise. Whether a parameter has a name
100      * is determined by the {@literal MethodParameters} attribute of
101      * the method which declares the parameter.
102      *
103      * @return true if and only if the parameter has a name according
104      * to the class file.
105      */
106     public boolean isNamePresent() {
107         return executable.hasRealParameterData() && name != null;
108     }
109 
110     /**
111      * Returns a string describing this parameter.  The format is the
112      * modifiers for the parameter, if any, in canonical order as
113      * recommended by <cite>The Java Language
114      * Specification</cite>, followed by the fully-qualified type of
115      * the parameter (excluding the last [] if the parameter is
116      * variable arity), followed by "..." if the parameter is variable
117      * arity, followed by a space, followed by the name of the
118      * parameter.
119      *
120      * @return A string representation of the parameter and associated
121      * information.
122      */
123     @Override
124     public String toString() {
125         final StringBuilder sb = new StringBuilder();
126         final Type type = getParameterizedType();
127         final String typename = type.getTypeName();
128 
129         sb.append(Modifier.toString(getModifiers()));
130 
131         if(0 != modifiers)
132             sb.append(' ');
133 
134         if(isVarArgs())
135             sb.append(typename.replaceFirst("\\[\\]$", "..."));
136         else
137             sb.append(typename);
138 
139         sb.append(' ');
140         sb.append(getName());
141 
142         return sb.toString();
143     }
144 
145     /**
146      * {@return the {@code Executable} declaring this parameter}
147      */
148     public Executable getDeclaringExecutable() {
149         return executable;
150     }
151 
152     /**
153      * {@return the Java language {@linkplain Modifier modifiers} for
154      * the parameter represented by this object}
155      *
156      * @jls 8.4.1 Formal Parameters
157      * @see <a
158      * href="{@docRoot}/java.base/java/lang/reflect/package-summary.html#LanguageJvmModel">Java
159      * programming language and JVM modeling in core reflection</a>
160      */
161     public int getModifiers() {
162         return modifiers;
163     }
164 
165     /**
166      * {@return an unmodifiable set of the {@linkplain AccessFlag
167      * access flags} for the parameter represented by this object,
168      * possibly empty}
169      *
170      * @see #getModifiers()
171      * @jvms 4.7.24 The MethodParameters Attribute
172      * @since 20
173      */
174     public Set<AccessFlag> accessFlags() {
175         return AccessFlag.maskToAccessFlags(getModifiers(),
176                                             AccessFlag.Location.METHOD_PARAMETER);
177     }
178 
179     /**
180      * Returns the name of the parameter.  If the parameter's name is
181      * {@linkplain #isNamePresent() present}, then this method returns
182      * the name provided by the class file. Otherwise, this method
183      * synthesizes a name of the form argN, where N is the index of
184      * the parameter in the descriptor of the method which declares
185      * the parameter.
186      *
187      * @return The name of the parameter, either provided by the class
188      *         file or synthesized if the class file does not provide
189      *         a name.
190      */
191     public String getName() {
192         // Note: empty strings as parameter names are now outlawed.
193         // The .isEmpty() is for compatibility with current JVM
194         // behavior.  It may be removed at some point.
195         if(name == null || name.isEmpty())
196             return "arg" + index;
197         else
198             return name;
199     }
200 
201     // Package-private accessor to the real name field.
202     String getRealName() {
203         return name;
204     }
205 
206     /**
207      * Returns a {@code Type} object that identifies the parameterized
208      * type for the parameter represented by this {@code Parameter}
209      * object.
210      *
211      * @return a {@code Type} object identifying the parameterized
212      * type of the parameter represented by this object
213      */
214     public Type getParameterizedType() {
215         Type tmp = parameterTypeCache;
216         if (null == tmp) {
217             tmp = executable.getAllGenericParameterTypes()[index];
218             parameterTypeCache = tmp;
219         }
220 
221         return tmp;
222     }
223 
224     private transient volatile Type parameterTypeCache;
225 
226     /**
227      * Returns a {@code Class} object that identifies the
228      * declared type for the parameter represented by this
229      * {@code Parameter} object.
230      *
231      * @return a {@code Class} object identifying the declared
232      * type of the parameter represented by this object
233      */
234     public Class<?> getType() {
235         Class<?> tmp = parameterClassCache;
236         if (null == tmp) {
237             tmp = executable.getParameterTypes()[index];
238             parameterClassCache = tmp;
239         }
240         return tmp;
241     }
242 
243     /**
244      * Returns an AnnotatedType object that represents the use of a type to
245      * specify the type of the formal parameter represented by this Parameter.
246      *
247      * @return an {@code AnnotatedType} object representing the use of a type
248      *         to specify the type of the formal parameter represented by this
249      *         Parameter
250      */
251     public AnnotatedType getAnnotatedType() {
252         // no caching for now
253         return executable.getAnnotatedParameterTypes()[index];
254     }
255 
256     private transient volatile Class<?> parameterClassCache;
257 
258     /**
259      * Returns {@code true} if this parameter is implicitly declared
260      * in source code; returns {@code false} otherwise.
261      *
262      * @return true if and only if this parameter is implicitly
263      * declared as defined by <cite>The Java Language
264      * Specification</cite>.
265      */
266     public boolean isImplicit() {
267         return Modifier.isMandated(getModifiers());
268     }
269 
270     /**
271      * Returns {@code true} if this parameter is neither implicitly
272      * nor explicitly declared in source code; returns {@code false}
273      * otherwise.
274      *
275      * @return true if and only if this parameter is a synthetic
276      * construct as defined by
277      * <cite>The Java Language Specification</cite>.
278      * @jls 13.1 The Form of a Binary
279      * @see <a
280      * href="{@docRoot}/java.base/java/lang/reflect/package-summary.html#LanguageJvmModel">Java
281      * programming language and JVM modeling in core reflection</a>
282      */
283     public boolean isSynthetic() {
284         return Modifier.isSynthetic(getModifiers());
285     }
286 
287     /**
288      * Returns {@code true} if this parameter represents a variable
289      * argument list; returns {@code false} otherwise.
290      *
291      * @return {@code true} if an only if this parameter represents a
292      * variable argument list.
293      */
294     public boolean isVarArgs() {
295         return executable.isVarArgs() &&
296             index == executable.getParameterCount() - 1;
297     }
298 
299 
300     /**
301      * {@inheritDoc}
302      * <p>Note that any annotation returned by this method is a
303      * declaration annotation.
304      * @throws NullPointerException {@inheritDoc}
305      */
306     @Override
307     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
308         Objects.requireNonNull(annotationClass);
309         return annotationClass.cast(declaredAnnotations().get(annotationClass));
310     }
311 
312     /**
313      * {@inheritDoc}
314      * <p>Note that any annotations returned by this method are
315      * declaration annotations.
316      *
317      * @throws NullPointerException {@inheritDoc}
318      */
319     @Override
320     public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
321         Objects.requireNonNull(annotationClass);
322 
323         return AnnotationSupport.getDirectlyAndIndirectlyPresent(declaredAnnotations(), annotationClass);
324     }
325 
326     /**
327      * {@inheritDoc}
328      * <p>Note that any annotations returned by this method are
329      * declaration annotations.
330      */
331     @Override
332     public Annotation[] getDeclaredAnnotations() {
333         return executable.getParameterAnnotations()[index];
334     }
335 
336     /**
337      * {@inheritDoc}
338      * <p>Note that any annotation returned by this method is a
339      * declaration annotation.
340      *
341      * @throws NullPointerException {@inheritDoc}
342      */
343     @Override
344     public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
345         // Only annotations on classes are inherited, for all other
346         // objects getDeclaredAnnotation is the same as
347         // getAnnotation.
348         return getAnnotation(annotationClass);
349     }
350 
351     /**
352      * {@inheritDoc}
353      * <p>Note that any annotations returned by this method are
354      * declaration annotations.
355      *
356      * @throws NullPointerException {@inheritDoc}
357      */
358     @Override
359     public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
360         // Only annotations on classes are inherited, for all other
361         // objects getDeclaredAnnotations is the same as
362         // getAnnotations.
363         return getAnnotationsByType(annotationClass);
364     }
365 
366     /**
367      * {@inheritDoc}
368      * <p>Note that any annotations returned by this method are
369      * declaration annotations.
370      */
371     @Override
372     public Annotation[] getAnnotations() {
373         return getDeclaredAnnotations();
374     }
375 
376     private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
377 
378     private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
379         if(null == declaredAnnotations) {
380             declaredAnnotations = new HashMap<>();
381             for (Annotation a : getDeclaredAnnotations())
382                 declaredAnnotations.put(a.annotationType(), a);
383         }
384         return declaredAnnotations;
385    }
386 
387 }