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