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