1 /* 2 * Copyright (c) 2019, 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 26 package java.lang.reflect; 27 28 import libcore.reflect.GenericSignatureParser; 29 import libcore.reflect.RecordComponents; 30 import libcore.util.EmptyArray; 31 32 import java.lang.annotation.Annotation; 33 import java.util.HashMap; 34 import java.util.Map; 35 import java.util.Objects; 36 37 /** 38 * A {@code RecordComponent} provides information about, and dynamic access to, a 39 * component of a record class. 40 * 41 * @see Class#getRecordComponents() 42 * @see java.lang.Record 43 * @jls 8.10 Record Classes 44 * @since 16 45 */ 46 public final class RecordComponent implements AnnotatedElement { 47 // declaring class 48 private Class<?> clazz; 49 private String name; 50 private Class<?> type; 51 private Method accessor; 52 private String signature; 53 // generic info repository; lazily initialized 54 // Android-remove: Remove unused fields. 55 // private transient FieldRepository genericInfo; 56 // private byte[] annotations; 57 // private byte[] typeAnnotations; 58 // private RecordComponent root; 59 60 // Android-added: Add parent and selfIndex to read generic signature and annotations lazily. 61 private RecordComponents parent; 62 private int selfIndex; 63 64 // only the JVM can create record components 65 // Android-remove: Remove unused constructor 66 // private RecordComponent() {} 67 68 // Android-added: Constructor used by libcore. 69 /** 70 * @hide 71 */ RecordComponent(Class<?> clazz, String name, Class<?> type, RecordComponents parent, int selfIndex)72 public RecordComponent(Class<?> clazz, String name, Class<?> type, RecordComponents parent, 73 int selfIndex) { 74 this.clazz = clazz; 75 this.name = name; 76 this.type = type; 77 this.parent = parent; 78 this.selfIndex = selfIndex; 79 this.signature = parent.getGenericSignature(selfIndex); 80 81 if (name != null) { 82 try { 83 accessor = clazz.getDeclaredMethod(name); 84 } catch (NoSuchMethodException e) { 85 // Keep this.accessor = null 86 } 87 } 88 } 89 90 /** 91 * Returns the name of this record component. 92 * 93 * @return the name of this record component 94 */ getName()95 public String getName() { 96 return name; 97 } 98 99 /** 100 * Returns a {@code Class} that identifies the declared type for this 101 * record component. 102 * 103 * @return a {@code Class} identifying the declared type of the component 104 * represented by this record component 105 */ getType()106 public Class<?> getType() { 107 return type; 108 } 109 110 /** 111 * Returns a {@code String} that describes the generic type signature for 112 * this record component. 113 * 114 * @return a {@code String} that describes the generic type signature for 115 * this record component 116 * 117 * @jvms 4.7.9.1 Signatures 118 */ getGenericSignature()119 public String getGenericSignature() { 120 return signature; 121 } 122 123 /** 124 * Returns a {@code Type} object that represents the declared type for 125 * this record component. 126 * 127 * <p>If the declared type of the record component is a parameterized type, 128 * the {@code Type} object returned reflects the actual type arguments used 129 * in the source code. 130 * 131 * <p>If the type of the underlying record component is a type variable or a 132 * parameterized type, it is created. Otherwise, it is resolved. 133 * 134 * @return a {@code Type} object that represents the declared type for 135 * this record component 136 * @throws GenericSignatureFormatError if the generic record component 137 * signature does not conform to the format specified in 138 * <cite>The Java Virtual Machine Specification</cite> 139 * @throws TypeNotPresentException if the generic type 140 * signature of the underlying record component refers to a non-existent 141 * type declaration 142 * @throws MalformedParameterizedTypeException if the generic 143 * signature of the underlying record component refers to a parameterized 144 * type that cannot be instantiated for any reason 145 */ getGenericType()146 public Type getGenericType() { 147 // Android-changed: getGenericType() implemented differently. 148 /* 149 if (getGenericSignature() != null) 150 return getGenericInfo().getGenericType(); 151 else 152 return getType(); 153 */ 154 String signatureAttribute = getGenericSignature(); 155 ClassLoader cl = clazz.getClassLoader(); 156 GenericSignatureParser parser = new GenericSignatureParser(cl); 157 parser.parseForField(clazz, signatureAttribute); 158 Type genericType = parser.fieldType; 159 if (genericType == null) { 160 genericType = getType(); 161 } 162 return genericType; 163 } 164 165 // BEGIN Android-removed: Unused code on ART. 166 /* 167 // Accessor for generic info repository 168 private FieldRepository getGenericInfo() { 169 // lazily initialize repository if necessary 170 if (genericInfo == null) { 171 // create and cache generic info repository 172 genericInfo = FieldRepository.make(getGenericSignature(), getFactory()); 173 } 174 return genericInfo; //return cached repository 175 } 176 177 // Accessor for factory 178 private GenericsFactory getFactory() { 179 Class<?> c = getDeclaringRecord(); 180 // create scope and factory 181 return CoreReflectionFactory.make(c, ClassScope.make(c)); 182 } 183 */ 184 // END Android-removed: Unused code on ART. 185 186 // BEGIN Android-removed: Annotated type isn't supported on Android. 187 /* 188 * Returns an {@code AnnotatedType} object that represents the use of a type to specify 189 * the declared type of this record component. 190 * 191 * @return an object representing the declared type of this record component 192 *//* 193 public AnnotatedType getAnnotatedType() { 194 return TypeAnnotationParser.buildAnnotatedType(typeAnnotations, 195 SharedSecrets.getJavaLangAccess(). 196 getConstantPool(getDeclaringRecord()), 197 this, 198 getDeclaringRecord(), 199 getGenericType(), 200 TypeAnnotation.TypeAnnotationTarget.FIELD); 201 } 202 */ 203 // END Android-removed: Annotated type isn't supported on Android. 204 205 /** 206 * Returns a {@code Method} that represents the accessor for this record 207 * component. 208 * 209 * @return a {@code Method} that represents the accessor for this record 210 * component 211 */ getAccessor()212 public Method getAccessor() { 213 return accessor; 214 } 215 216 /** 217 * {@inheritDoc} 218 * <p>Note that any annotation returned by this method is a 219 * declaration annotation. 220 * @throws NullPointerException {@inheritDoc} 221 */ 222 @Override getAnnotation(Class<T> annotationClass)223 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 224 Objects.requireNonNull(annotationClass); 225 return annotationClass.cast(declaredAnnotations().get(annotationClass)); 226 } 227 228 private transient volatile Map<Class<? extends Annotation>, Annotation> declaredAnnotations; 229 declaredAnnotations()230 private Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { 231 Map<Class<? extends Annotation>, Annotation> declAnnos; 232 if ((declAnnos = declaredAnnotations) == null) { 233 synchronized (this) { 234 if ((declAnnos = declaredAnnotations) == null) { 235 // Android-changed: Re-implement on top of ART. 236 /* 237 RecordComponent root = this.root; 238 if (root != null) { 239 declAnnos = root.declaredAnnotations(); 240 } else { 241 declAnnos = AnnotationParser.parseAnnotations( 242 annotations, 243 SharedSecrets.getJavaLangAccess() 244 .getConstantPool(getDeclaringRecord()), 245 getDeclaringRecord()); 246 } 247 */ 248 Annotation[] annotations = parent.getVisibleAnnotations(selfIndex); 249 if (annotations == null) { 250 annotations = EmptyArray.ANNOTATION; 251 } 252 declAnnos = new HashMap<>(annotations.length); 253 for (Annotation a : annotations) { 254 declAnnos.put(a.annotationType(), a); 255 } 256 declaredAnnotations = declAnnos; 257 } 258 } 259 } 260 return declAnnos; 261 } 262 263 /** 264 * {@inheritDoc} 265 * <p>Note that any annotations returned by this method are 266 * declaration annotations. 267 */ 268 @Override getAnnotations()269 public Annotation[] getAnnotations() { 270 return getDeclaredAnnotations(); 271 } 272 273 /** 274 * {@inheritDoc} 275 * <p>Note that any annotations returned by this method are 276 * declaration annotations. 277 */ 278 @Override getDeclaredAnnotations()279 public Annotation[] getDeclaredAnnotations() { 280 // Android-changed: Re-implement on top of ART. 281 // return AnnotationParser.toArray(declaredAnnotations()); 282 return declaredAnnotations().values().toArray(EmptyArray.ANNOTATION); 283 } 284 285 /** 286 * Returns a string describing this record component. The format is 287 * the record component type, followed by a space, followed by the name 288 * of the record component. 289 * For example: 290 * <pre> 291 * java.lang.String name 292 * int age 293 * </pre> 294 * 295 * @return a string describing this record component 296 */ toString()297 public String toString() { 298 return (getType().getTypeName() + " " + getName()); 299 } 300 301 /** 302 * Returns the record class which declares this record component. 303 * 304 * @return The record class declaring this record component. 305 */ getDeclaringRecord()306 public Class<?> getDeclaringRecord() { 307 return clazz; 308 } 309 } 310