1 /* 2 * Copyright (c) 2012, 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.Map; 29 import java.util.HashMap; 30 31 public final class Parameter implements AnnotatedElement { 32 33 private String name; 34 private int modifiers; 35 private Executable executable; 36 private int index; 37 38 Parameter(String name, 39 int modifiers, 40 Executable executable, 41 int index) { 42 this.name = name; 43 this.modifiers = modifiers; 44 this.executable = executable; 45 this.index = index; 46 } 47 48 Parameter(Parameter p) { 49 this.name = p.name; 50 this.modifiers = p.modifiers; 51 this.executable = p.executable; 52 this.index = p.index; 53 } 54 55 // Compare by the declaring executable and index only. Note: this 56 // will equate the "same" parameter under a different name and 57 // with different modifiers, which should never happen. This may 58 // need to be revised in the future. 59 public boolean equals(Object obj) { 60 if(null != obj && obj instanceof Parameter) { 61 Parameter other = (Parameter)obj; 62 return (other.executable.equals(executable) && 63 other.index == index); 64 } 65 return false; 66 } 67 68 public int hashCode() { 69 return executable.hashCode() ^ index; 70 } 71 72 // As per the spec... 73 public String toString() { 74 final StringBuilder sb = new StringBuilder(); 75 final Type type = getParameterizedType(); 76 final String typename = (type instanceof Class)? 77 Field.getTypeName((Class)type): 78 (type.toString()); 79 80 sb.append(Modifier.toString(getModifiers())); 81 sb.append(" "); 82 83 if(isVarArgs()) 84 sb.append(typename.replaceFirst("\\[\\]$", "...")); 85 else 86 sb.append(typename); 87 88 sb.append(" "); 89 sb.append(name); 90 91 return sb.toString(); 92 } 93 94 public Executable getDeclaringExecutable() { 95 return executable; 96 } 97 98 public int getModifiers() { 99 return modifiers; 100 } 101 102 /** 103 * Returns the name of the field represented by this 104 * {@code Parameter} object. 105 */ 106 public String getName() { 107 return name; 108 } 109 110 /** 111 * Returns a {@code Type} object that identifies the parameterized 112 * type for the parameter represented by this {@code Parameter} 113 * object. 114 * 115 * @return a {@code Type} object identifying the parameterized 116 * type of the parameter represented by this object 117 */ 118 public Type getParameterizedType() { 119 if (null == parameterTypeCache) 120 parameterTypeCache = executable.getGenericParameterTypes(); 121 122 return parameterTypeCache[index]; 123 } 124 125 private transient Type[] parameterTypeCache = null; 126 127 /** 128 * Returns a {@code Class} object that identifies the 129 * declared type for the parameter represented by this 130 * {@code Parameter} object. 131 * 132 * @return a {@code Class} object identifying the declared 133 * type of the parameter represented by this object 134 */ 135 public Class<?> getType() { 136 if (null == parameterClassCache) 137 parameterClassCache = executable.getParameterTypes(); 138 139 return parameterClassCache[index]; 140 } 141 142 private transient Class<?>[] parameterClassCache = null; 143 144 // TODO: Replace with implementation once the details are sorted. 145 public boolean isSynthesized() { return false; } 146 147 /** 148 * Returns {@code true} if this parameter is a synthetic 149 * construct; returns {@code false} otherwise. 150 * 151 * @return true if and only if this parameter is a synthetic 152 * construct as defined by 153 * <cite>The Java™ Language Specification</cite>. 154 */ 155 public boolean isSynthetic() { 156 return Modifier.isSynthetic(getModifiers()); 157 } 158 159 /** 160 * Returns {@code true} if this parameter represents a variable 161 * argument list; returns {@code false} otherwise. 162 * 163 * @return {@code true} if an only if this parameter represents a 164 * variable argument list. 165 */ 166 public boolean isVarArgs() { 167 return executable.isVarArgs() && 168 index == executable.getNumParameters() - 1; 169 } 170 171 @SuppressWarnings("unchecked") 172 public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { 173 if (annotationClass == null) 174 throw new NullPointerException(); 175 176 return (T)declaredAnnotations().get(annotationClass); 177 } 178 179 public <T extends Annotation> T getDeclaredAnnotations(Class<T> annotationClass) { 180 return getDeclaredAnnotation(annotationClass); 181 } 182 183 // We cache the annotations here, to avoid having to copy them 184 // repeatedly. 185 private transient Annotation[] annotationCache = null; 186 187 public Annotation[] getDeclaredAnnotations() { 188 if(null == annotationCache) 189 annotationCache = executable.getParameterAnnotations()[index]; 190 191 return annotationCache.clone(); 192 } 193 194 /** 195 * @throws NullPointerException {@inheritDoc} 196 */ 197 @SuppressWarnings("unchecked") 198 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 199 return getDeclaredAnnotation(annotationClass); 200 } 201 202 public <T extends Annotation> T getAnnotations(Class<T> annotationClass) { 203 return getDeclaredAnnotations(annotationClass); 204 } 205 206 public Annotation[] getAnnotations() { 207 return getDeclaredAnnotations(); 208 } 209 210 /** 211 * @throws NullPointerException {@inheritDoc} 212 */ 213 public boolean isAnnotationPresent( 214 Class<? extends Annotation> annotationClass) { 215 return getAnnotation(annotationClass) != null; 216 } 217 218 private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations; 219 220 private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { 221 if(null == declaredAnnotations) { 222 declaredAnnotations = 223 new HashMap<Class<? extends Annotation>, Annotation>(); 224 Annotation[] ann = getDeclaredAnnotations(); 225 for(int i = 0; i < ann.length; i++) 226 declaredAnnotations.put(ann[i].annotationType(), ann[i]); 227 } 228 return declaredAnnotations; 229 } 230 231 }