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 }