1 /*
2  * Copyright (c) 2013, 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 package sun.reflect.annotation;
26 
27 import java.lang.annotation.Annotation;
28 import java.lang.annotation.AnnotationFormatError;
29 import java.lang.reflect.AnnotatedElement;
30 import java.nio.ByteBuffer;
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 /**
35  * A TypeAnnotation contains all the information needed to transform type
36  * annotations on declarations in the class file to actual Annotations in
37  * AnnotatedType instances.
38  *
39  * TypeAnnotaions contain a base Annotation, location info (which lets you
40  * distinguish between '@A Inner.@B Outer' in for example nested types),
41  * target info and the declaration the TypeAnnotaiton was parsed from.
42  */
43 public final class TypeAnnotation {
44     private final TypeAnnotationTargetInfo targetInfo;
45     private final LocationInfo loc;
46     private final Annotation annotation;
47     private final AnnotatedElement baseDeclaration;
48 
TypeAnnotation(TypeAnnotationTargetInfo targetInfo, LocationInfo loc, Annotation annotation, AnnotatedElement baseDeclaration)49     public TypeAnnotation(TypeAnnotationTargetInfo targetInfo,
50                           LocationInfo loc,
51                           Annotation annotation,
52                           AnnotatedElement baseDeclaration) {
53         this.targetInfo = targetInfo;
54         this.loc = loc;
55         this.annotation = annotation;
56         this.baseDeclaration = baseDeclaration;
57     }
58 
getTargetInfo()59     public TypeAnnotationTargetInfo getTargetInfo() {
60         return targetInfo;
61     }
getAnnotation()62     public Annotation getAnnotation() {
63         return annotation;
64     }
getBaseDeclaration()65     public AnnotatedElement getBaseDeclaration() {
66         return baseDeclaration;
67     }
getLocationInfo()68     public LocationInfo getLocationInfo() {
69         return loc;
70     }
71 
filter(TypeAnnotation[] typeAnnotations, TypeAnnotationTarget predicate)72     public static List<TypeAnnotation> filter(TypeAnnotation[] typeAnnotations,
73                                               TypeAnnotationTarget predicate) {
74         ArrayList<TypeAnnotation> typeAnnos = new ArrayList<>(typeAnnotations.length);
75         for (TypeAnnotation t : typeAnnotations)
76             if (t.getTargetInfo().getTarget() == predicate)
77                 typeAnnos.add(t);
78         typeAnnos.trimToSize();
79         return typeAnnos;
80     }
81 
82     public static enum TypeAnnotationTarget {
83         CLASS_TYPE_PARAMETER,
84         METHOD_TYPE_PARAMETER,
85         CLASS_EXTENDS,
86         CLASS_IMPLEMENTS, // Not in the spec
87         CLASS_TYPE_PARAMETER_BOUND,
88         METHOD_TYPE_PARAMETER_BOUND,
89         FIELD,
90         METHOD_RETURN,
91         METHOD_RECEIVER,
92         METHOD_FORMAL_PARAMETER,
93         THROWS,
94         /**
95          * {@preview Associated with records, a preview feature of the Java language.
96          *
97          *           This enum constant is associated with <i>records</i>, a preview
98          *           feature of the Java language. Preview features
99          *           may be removed in a future release, or upgraded to permanent
100          *           features of the Java language.}
101          * @since 14
102          */
103         @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
104                                      essentialAPI=false)
105         RECORD_COMPONENT;
106     }
107 
108     public static final class TypeAnnotationTargetInfo {
109         private final TypeAnnotationTarget target;
110         private final int count;
111         private final int secondaryIndex;
112         private static final int UNUSED_INDEX = -2; // this is not a valid index in the 308 spec
113 
TypeAnnotationTargetInfo(TypeAnnotationTarget target)114         public TypeAnnotationTargetInfo(TypeAnnotationTarget target) {
115             this(target, UNUSED_INDEX, UNUSED_INDEX);
116         }
117 
TypeAnnotationTargetInfo(TypeAnnotationTarget target, int count)118         public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
119                                         int count) {
120             this(target, count, UNUSED_INDEX);
121         }
122 
TypeAnnotationTargetInfo(TypeAnnotationTarget target, int count, int secondaryIndex)123         public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
124                                         int count,
125                                         int secondaryIndex) {
126             this.target = target;
127             this.count = count;
128             this.secondaryIndex = secondaryIndex;
129         }
130 
getTarget()131         public TypeAnnotationTarget getTarget() {
132             return target;
133         }
getCount()134         public int getCount() {
135             return count;
136         }
getSecondaryIndex()137         public int getSecondaryIndex() {
138             return secondaryIndex;
139         }
140 
141         @Override
toString()142         public String toString() {
143             return "" + target + ": " + count + ", " + secondaryIndex;
144         }
145     }
146 
147     public static final class LocationInfo {
148         private final int depth;
149         private final Location[] locations;
150 
LocationInfo()151         private LocationInfo() {
152             this(0, new Location[0]);
153         }
LocationInfo(int depth, Location[] locations)154         private LocationInfo(int depth, Location[] locations) {
155             this.depth = depth;
156             this.locations = locations;
157         }
158 
159         public static final LocationInfo BASE_LOCATION = new LocationInfo();
160 
parseLocationInfo(ByteBuffer buf)161         public static LocationInfo parseLocationInfo(ByteBuffer buf) {
162             int depth = buf.get() & 0xFF;
163             if (depth == 0)
164                 return BASE_LOCATION;
165             Location[] locations = new Location[depth];
166             for (int i = 0; i < depth; i++) {
167                 byte tag = buf.get();
168                 short index = (short)(buf.get() & 0xFF);
169                 if (!(tag == 0 || tag == 1 | tag == 2 || tag == 3))
170                     throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
171                 if (tag != 3 && index != 0)
172                     throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
173                 locations[i] = new Location(tag, index);
174             }
175             return new LocationInfo(depth, locations);
176         }
177 
pushArray()178         public LocationInfo pushArray() {
179             return pushLocation((byte)0, (short)0);
180         }
181 
pushInner()182         public LocationInfo pushInner() {
183             return pushLocation((byte)1, (short)0);
184         }
185 
pushWildcard()186         public LocationInfo pushWildcard() {
187             return pushLocation((byte) 2, (short) 0);
188         }
189 
pushTypeArg(short index)190         public LocationInfo pushTypeArg(short index) {
191             return pushLocation((byte) 3, index);
192         }
193 
pushLocation(byte tag, short index)194         public LocationInfo pushLocation(byte tag, short index) {
195             int newDepth = this.depth + 1;
196             Location[] res = new Location[newDepth];
197             System.arraycopy(this.locations, 0, res, 0, depth);
198             res[newDepth - 1] = new Location(tag, (short)(index & 0xFF));
199             return new LocationInfo(newDepth, res);
200         }
201 
202         /**
203          * Pops a location matching {@code tag}, or returns {@code null}
204          * if no matching location was found.
205          */
popLocation(byte tag)206         public LocationInfo popLocation(byte tag) {
207             if (depth == 0 || locations[depth - 1].tag != tag) {
208                 return null;
209             }
210             Location[] res = new Location[depth - 1];
211             System.arraycopy(locations, 0, res, 0, depth - 1);
212             return new LocationInfo(depth - 1, res);
213         }
214 
filter(TypeAnnotation[] ta)215         public TypeAnnotation[] filter(TypeAnnotation[] ta) {
216             ArrayList<TypeAnnotation> l = new ArrayList<>(ta.length);
217             for (TypeAnnotation t : ta) {
218                 if (isSameLocationInfo(t.getLocationInfo()))
219                     l.add(t);
220             }
221             return l.toArray(AnnotatedTypeFactory.EMPTY_TYPE_ANNOTATION_ARRAY);
222         }
223 
isSameLocationInfo(LocationInfo other)224         boolean isSameLocationInfo(LocationInfo other) {
225             if (depth != other.depth)
226                 return false;
227             for (int i = 0; i < depth; i++)
228                 if (!locations[i].isSameLocation(other.locations[i]))
229                     return false;
230             return true;
231         }
232 
233         public static final class Location {
234             public final byte tag;
235             public final short index;
236 
isSameLocation(Location other)237             boolean isSameLocation(Location other) {
238                 return tag == other.tag && index == other.index;
239             }
240 
Location(byte tag, short index)241             public Location(byte tag, short index) {
242                 this.tag = tag;
243                 this.index = index;
244             }
245         }
246     }
247 
248     @Override
toString()249     public String toString() {
250         return annotation.toString() + " with Targetnfo: " +
251             targetInfo.toString() + " on base declaration: " +
252             baseDeclaration.toString();
253     }
254 }
255