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 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 59 public TypeAnnotationTargetInfo getTargetInfo() { 60 return targetInfo; 61 } 62 public Annotation getAnnotation() { 63 return annotation; 64 } 65 public AnnotatedElement getBaseDeclaration() { 66 return baseDeclaration; 67 } 68 public LocationInfo getLocationInfo() { 69 return loc; 70 } 71 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 102 public TypeAnnotationTargetInfo(TypeAnnotationTarget target) { 103 this(target, UNUSED_INDEX, UNUSED_INDEX); 104 } 105 106 public TypeAnnotationTargetInfo(TypeAnnotationTarget target, 107 int count) { 108 this(target, count, UNUSED_INDEX); 109 } 110 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 119 public TypeAnnotationTarget getTarget() { 120 return target; 121 } 122 public int getCount() { 123 return count; 124 } 125 public int getSecondaryIndex() { 126 return secondaryIndex; 127 } 128 129 @Override 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 139 private LocationInfo() { 140 this(0, new Location[0]); 141 } 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 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 166 public LocationInfo pushArray() { 167 return pushLocation((byte)0, (short)0); 168 } 169 170 public LocationInfo pushInner() { 171 return pushLocation((byte)1, (short)0); 172 } 173 174 public LocationInfo pushWildcard() { 175 return pushLocation((byte) 2, (short) 0); 176 } 177 178 public LocationInfo pushTypeArg(short index) { 179 return pushLocation((byte) 3, index); 180 } 181 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 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 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 212 boolean isSameLocation(Location other) { 213 return tag == other.tag && index == other.index; 214 } 215 216 public Location(byte tag, short index) { 217 this.tag = tag; 218 this.index = index; 219 } 220 } 221 } 222 223 @Override 224 public String toString() { 225 return annotation.toString() + " with Targetnfo: " + 226 targetInfo.toString() + " on base declaration: " + 227 baseDeclaration.toString(); 228 } 229 }