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