1 /* 2 * Copyright (c) 2013, 2020, 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 if(obj instanceof Parameter) { 81 Parameter other = (Parameter)obj; 82 return (other.executable.equals(executable) && 83 other.index == index); 84 } 85 return false; 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 executable.hasRealParameterData() && 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())); 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 */ 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 */ 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 */ 178 public String getName() { 179 // Note: empty strings as parameter names are now outlawed. 180 // The .isEmpty() is for compatibility with current JVM 181 // behavior. It may be removed at some point. 182 if(name == null || name.isEmpty()) 183 return "arg" + index; 184 else 185 return name; 186 } 187 188 // Package-private accessor to the real name field. 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 */ 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 */ 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 /** 231 * Returns an AnnotatedType object that represents the use of a type to 232 * specify the type of the formal parameter represented by this Parameter. 233 * 234 * @return an {@code AnnotatedType} object representing the use of a type 235 * to specify the type of the formal parameter represented by this 236 * Parameter 237 */ 238 public AnnotatedType getAnnotatedType() { 239 // no caching for now 240 return executable.getAnnotatedParameterTypes()[index]; 241 } 242 243 private transient volatile Class<?> parameterClassCache; 244 245 /** 246 * Returns {@code true} if this parameter is implicitly declared 247 * in source code; returns {@code false} otherwise. 248 * 249 * @return true if and only if this parameter is implicitly 250 * declared as defined by <cite>The Java™ Language 251 * Specification</cite>. 252 */ 253 public boolean isImplicit() { 254 return Modifier.isMandated(getModifiers()); 255 } 256 257 /** 258 * Returns {@code true} if this parameter is neither implicitly 259 * nor explicitly declared in source code; returns {@code false} 260 * otherwise. 261 * 262 * @jls 13.1 The Form of a Binary 263 * @return true if and only if this parameter is a synthetic 264 * construct as defined by 265 * <cite>The Java™ Language Specification</cite>. 266 */ 267 public boolean isSynthetic() { 268 return Modifier.isSynthetic(getModifiers()); 269 } 270 271 /** 272 * Returns {@code true} if this parameter represents a variable 273 * argument list; returns {@code false} otherwise. 274 * 275 * @return {@code true} if an only if this parameter represents a 276 * variable argument list. 277 */ 278 public boolean isVarArgs() { 279 return executable.isVarArgs() && 280 index == executable.getParameterCount() - 1; 281 } 282 283 284 /** 285 * {@inheritDoc} 286 * <p>Note that any annotation returned by this method is a 287 * declaration annotation. 288 * @throws NullPointerException {@inheritDoc} 289 */ 290 @Override 291 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 292 Objects.requireNonNull(annotationClass); 293 return annotationClass.cast(declaredAnnotations().get(annotationClass)); 294 } 295 296 /** 297 * {@inheritDoc} 298 * <p>Note that any annotations returned by this method are 299 * declaration annotations. 300 * 301 * @throws NullPointerException {@inheritDoc} 302 */ 303 @Override 304 public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) { 305 Objects.requireNonNull(annotationClass); 306 307 return AnnotationSupport.getDirectlyAndIndirectlyPresent(declaredAnnotations(), annotationClass); 308 } 309 310 /** 311 * {@inheritDoc} 312 * <p>Note that any annotations returned by this method are 313 * declaration annotations. 314 */ 315 @Override 316 public Annotation[] getDeclaredAnnotations() { 317 return executable.getParameterAnnotations()[index]; 318 } 319 320 /** 321 * {@inheritDoc} 322 * <p>Note that any annotation returned by this method is a 323 * declaration annotation. 324 * 325 * @throws NullPointerException {@inheritDoc} 326 */ 327 @Override 328 public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { 329 // Only annotations on classes are inherited, for all other 330 // objects getDeclaredAnnotation is the same as 331 // getAnnotation. 332 return getAnnotation(annotationClass); 333 } 334 335 /** 336 * {@inheritDoc} 337 * <p>Note that any annotations returned by this method are 338 * declaration annotations. 339 * 340 * @throws NullPointerException {@inheritDoc} 341 */ 342 @Override 343 public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { 344 // Only annotations on classes are inherited, for all other 345 // objects getDeclaredAnnotations is the same as 346 // getAnnotations. 347 return getAnnotationsByType(annotationClass); 348 } 349 350 /** 351 * {@inheritDoc} 352 * <p>Note that any annotations returned by this method are 353 * declaration annotations. 354 */ 355 @Override 356 public Annotation[] getAnnotations() { 357 return getDeclaredAnnotations(); 358 } 359 360 private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations; 361 362 private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { 363 if(null == declaredAnnotations) { 364 declaredAnnotations = new HashMap<>(); 365 for (Annotation a : getDeclaredAnnotations()) 366 declaredAnnotations.put(a.annotationType(), a); 367 } 368 return declaredAnnotations; 369 } 370 371 }