1 /*
2  * Copyright (c) 2013, 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 
96     public static final class TypeAnnotationTargetInfo {
97         private final TypeAnnotationTarget target;
98         private final int count;
99         private final int secondaryIndex;
100         private static final int UNUSED_INDEX = -2; // this is not a valid index in the 308 spec
101 
TypeAnnotationTargetInfo(TypeAnnotationTarget target)102         public TypeAnnotationTargetInfo(TypeAnnotationTarget target) {
103             this(target, UNUSED_INDEX, UNUSED_INDEX);
104         }
105 
TypeAnnotationTargetInfo(TypeAnnotationTarget target, int count)106         public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
107                                         int count) {
108             this(target, count, UNUSED_INDEX);
109         }
110 
TypeAnnotationTargetInfo(TypeAnnotationTarget target, int count, int secondaryIndex)111         public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
112                                         int count,
113                                         int secondaryIndex) {
114             this.target = target;
115             this.count = count;
116             this.secondaryIndex = secondaryIndex;
117         }
118 
getTarget()119         public TypeAnnotationTarget getTarget() {
120             return target;
121         }
getCount()122         public int getCount() {
123             return count;
124         }
getSecondaryIndex()125         public int getSecondaryIndex() {
126             return secondaryIndex;
127         }
128 
129         @Override
toString()130         public String toString() {
131             return "" + target + ": " + count + ", " + secondaryIndex;
132         }
133     }
134 
135     public static final class LocationInfo {
136         private final int depth;
137         private final Location[] locations;
138 
LocationInfo()139         private LocationInfo() {
140             this(0, new Location[0]);
141         }
LocationInfo(int depth, Location[] locations)142         private LocationInfo(int depth, Location[] locations) {
143             this.depth = depth;
144             this.locations = locations;
145         }
146 
147         public static final LocationInfo BASE_LOCATION = new LocationInfo();
148 
parseLocationInfo(ByteBuffer buf)149         public static LocationInfo parseLocationInfo(ByteBuffer buf) {
150             int depth = buf.get() & 0xFF;
151             if (depth == 0)
152                 return BASE_LOCATION;
153             Location[] locations = new Location[depth];
154             for (int i = 0; i < depth; i++) {
155                 byte tag = buf.get();
156                 short index = (short)(buf.get() & 0xFF);
157                 if (!(tag == 0 || tag == 1 | tag == 2 || tag == 3))
158                     throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
159                 if (tag != 3 && index != 0)
160                     throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
161                 locations[i] = new Location(tag, index);
162             }
163             return new LocationInfo(depth, locations);
164         }
165 
pushArray()166         public LocationInfo pushArray() {
167             return pushLocation((byte)0, (short)0);
168         }
169 
pushInner()170         public LocationInfo pushInner() {
171             return pushLocation((byte)1, (short)0);
172         }
173 
pushWildcard()174         public LocationInfo pushWildcard() {
175             return pushLocation((byte) 2, (short) 0);
176         }
177 
pushTypeArg(short index)178         public LocationInfo pushTypeArg(short index) {
179             return pushLocation((byte) 3, index);
180         }
181 
pushLocation(byte tag, short index)182         public LocationInfo pushLocation(byte tag, short index) {
183             int newDepth = this.depth + 1;
184             Location[] res = new Location[newDepth];
185             System.arraycopy(this.locations, 0, res, 0, depth);
186             res[newDepth - 1] = new Location(tag, (short)(index & 0xFF));
187             return new LocationInfo(newDepth, res);
188         }
189 
filter(TypeAnnotation[] ta)190         public TypeAnnotation[] filter(TypeAnnotation[] ta) {
191             ArrayList<TypeAnnotation> l = new ArrayList<>(ta.length);
192             for (TypeAnnotation t : ta) {
193                 if (isSameLocationInfo(t.getLocationInfo()))
194                     l.add(t);
195             }
196             return l.toArray(new TypeAnnotation[0]);
197         }
198 
isSameLocationInfo(LocationInfo other)199         boolean isSameLocationInfo(LocationInfo other) {
200             if (depth != other.depth)
201                 return false;
202             for (int i = 0; i < depth; i++)
203                 if (!locations[i].isSameLocation(other.locations[i]))
204                     return false;
205             return true;
206         }
207 
208         public static final class Location {
209             public final byte tag;
210             public final short index;
211 
isSameLocation(Location other)212             boolean isSameLocation(Location other) {
213                 return tag == other.tag && index == other.index;
214             }
215 
Location(byte tag, short index)216             public Location(byte tag, short index) {
217                 this.tag = tag;
218                 this.index = index;
219             }
220         }
221     }
222 
223     @Override
toString()224     public String toString() {
225         return annotation.toString() + " with Targetnfo: " +
226             targetInfo.toString() + " on base declaration: " +
227             baseDeclaration.toString();
228     }
229 }
230