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