1 /* 2 * Copyright (c) 2019, 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 jdk.internal.access.SharedSecrets; 29 import sun.reflect.annotation.AnnotationParser; 30 import sun.reflect.annotation.TypeAnnotation; 31 import sun.reflect.annotation.TypeAnnotationParser; 32 import sun.reflect.generics.factory.CoreReflectionFactory; 33 import sun.reflect.generics.factory.GenericsFactory; 34 import sun.reflect.generics.repository.FieldRepository; 35 import sun.reflect.generics.scope.ClassScope; 36 import java.lang.annotation.Annotation; 37 import java.util.Map; 38 import java.util.Objects; 39 40 /** 41 * {@preview Associated with records, a preview feature of the Java language. 42 * 43 * This class is associated with <i>records</i>, a preview 44 * feature of the Java language. Preview features 45 * may be removed in a future release, or upgraded to permanent 46 * features of the Java language.} 47 * 48 * A {@code RecordComponent} provides information about, and dynamic access to, a 49 * component of a record class. 50 * 51 * @see Class#getRecordComponents() 52 * @see java.lang.Record 53 * @jls 8.10 Record Types 54 * @since 14 55 */ 56 @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, 57 essentialAPI=false) 58 public final class RecordComponent implements AnnotatedElement { 59 // declaring class 60 private Class<?> clazz; 61 private String name; 62 private Class<?> type; 63 private Method accessor; 64 private String signature; 65 // generic info repository; lazily initialized 66 private transient FieldRepository genericInfo; 67 private byte[] annotations; 68 private byte[] typeAnnotations; 69 @SuppressWarnings("preview") 70 private RecordComponent root; 71 72 // only the JVM can create record components 73 private RecordComponent() {} 74 75 /** 76 * Returns the name of this record component. 77 * 78 * @return the name of this record component 79 */ 80 public String getName() { 81 return name; 82 } 83 84 /** 85 * Returns a {@code Class} that identifies the declared type for this 86 * record component. 87 * 88 * @return a {@code Class} identifying the declared type of the component 89 * represented by this record component 90 */ 91 public Class<?> getType() { 92 return type; 93 } 94 95 /** 96 * Returns a {@code String} that describes the generic type signature for 97 * this record component. 98 * 99 * @return a {@code String} that describes the generic type signature for 100 * this record component 101 * 102 * @jvms 4.7.9.1 Signatures 103 */ 104 public String getGenericSignature() { 105 return signature; 106 } 107 108 /** 109 * Returns a {@code Type} object that represents the declared type for 110 * this record component. 111 * 112 * <p>If the declared type of the record component is a parameterized type, 113 * the {@code Type} object returned reflects the actual type arguments used 114 * in the source code. 115 * 116 * <p>If the type of the underlying record component is a type variable or a 117 * parameterized type, it is created. Otherwise, it is resolved. 118 * 119 * @return a {@code Type} object that represents the declared type for 120 * this record component 121 * @throws GenericSignatureFormatError if the generic record component 122 * signature does not conform to the format specified in 123 * <cite>The Java™ Virtual Machine Specification</cite> 124 * @throws TypeNotPresentException if the generic type 125 * signature of the underlying record component refers to a non-existent 126 * type declaration 127 * @throws MalformedParameterizedTypeException if the generic 128 * signature of the underlying record component refers to a parameterized 129 * type that cannot be instantiated for any reason 130 */ 131 public Type getGenericType() { 132 if (getGenericSignature() != null) 133 return getGenericInfo().getGenericType(); 134 else 135 return getType(); 136 } 137 138 // Accessor for generic info repository 139 private FieldRepository getGenericInfo() { 140 // lazily initialize repository if necessary 141 if (genericInfo == null) { 142 // create and cache generic info repository 143 genericInfo = FieldRepository.make(getGenericSignature(), getFactory()); 144 } 145 return genericInfo; //return cached repository 146 } 147 148 // Accessor for factory 149 private GenericsFactory getFactory() { 150 Class<?> c = getDeclaringRecord(); 151 // create scope and factory 152 return CoreReflectionFactory.make(c, ClassScope.make(c)); 153 } 154 155 /** 156 * Returns an {@code AnnotatedType} object that represents the use of a type to specify 157 * the declared type of this record component. 158 * 159 * @return an object representing the declared type of this record component 160 */ 161 public AnnotatedType getAnnotatedType() { 162 return TypeAnnotationParser.buildAnnotatedType(typeAnnotations, 163 SharedSecrets.getJavaLangAccess(). 164 getConstantPool(getDeclaringRecord()), 165 this, 166 getDeclaringRecord(), 167 getGenericType(), 168 TypeAnnotation.TypeAnnotationTarget.FIELD); 169 } 170 171 /** 172 * Returns a {@code Method} that represents the accessor for this record 173 * component. 174 * 175 * @return a {@code Method} that represents the accessor for this record 176 * component 177 */ 178 public Method getAccessor() { 179 return accessor; 180 } 181 182 /** 183 * {@inheritDoc} 184 * <p>Note that any annotation returned by this method is a 185 * declaration annotation. 186 * @throws NullPointerException {@inheritDoc} 187 */ 188 @Override 189 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 190 Objects.requireNonNull(annotationClass); 191 return annotationClass.cast(declaredAnnotations().get(annotationClass)); 192 } 193 194 private transient volatile Map<Class<? extends Annotation>, Annotation> declaredAnnotations; 195 196 private Map<Class<? extends Annotation>, Annotation> declaredAnnotations() { 197 Map<Class<? extends Annotation>, Annotation> declAnnos; 198 if ((declAnnos = declaredAnnotations) == null) { 199 synchronized (this) { 200 if ((declAnnos = declaredAnnotations) == null) { 201 @SuppressWarnings("preview") 202 RecordComponent root = this.root; 203 if (root != null) { 204 declAnnos = root.declaredAnnotations(); 205 } else { 206 declAnnos = AnnotationParser.parseAnnotations( 207 annotations, 208 SharedSecrets.getJavaLangAccess() 209 .getConstantPool(getDeclaringRecord()), 210 getDeclaringRecord()); 211 } 212 declaredAnnotations = declAnnos; 213 } 214 } 215 } 216 return declAnnos; 217 } 218 219 /** 220 * {@inheritDoc} 221 * <p>Note that any annotations returned by this method are 222 * declaration annotations. 223 */ 224 @Override 225 public Annotation[] getAnnotations() { 226 return getDeclaredAnnotations(); 227 } 228 229 /** 230 * {@inheritDoc} 231 * <p>Note that any annotations returned by this method are 232 * declaration annotations. 233 */ 234 @Override 235 public Annotation[] getDeclaredAnnotations() { return AnnotationParser.toArray(declaredAnnotations()); } 236 237 /** 238 * Returns a string describing this record component. The format is 239 * the record component type, followed by a space, followed by the name 240 * of the record component. 241 * For example: 242 * <pre> 243 * java.lang.String name 244 * int age 245 * </pre> 246 * 247 * @return a string describing this record component 248 */ 249 public String toString() { 250 return (getType().getTypeName() + " " + getName()); 251 } 252 253 /** 254 * Returns the record class which declares this record component. 255 * 256 * @return The record class declaring this record component. 257 */ 258 public Class<?> getDeclaringRecord() { 259 return clazz; 260 } 261 }