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 26 package sun.reflect.annotation; 27 28 import java.lang.annotation.*; 29 import java.lang.reflect.*; 30 import java.nio.ByteBuffer; 31 import java.nio.BufferUnderflowException; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.List; 35 import java.util.HashMap; 36 import java.util.LinkedHashMap; 37 import java.util.Map; 38 import sun.misc.JavaLangAccess; 39 import sun.reflect.ConstantPool; 40 import static sun.reflect.annotation.TypeAnnotation.*; 41 42 public class TypeAnnotationParser { 43 // Position codes 44 private static final byte CLASS_TYPE_PARAMETER_CODE = 0x00; 45 private static final byte METHOD_TYPE_PARAMETER_CODE = 0x02; 46 private static final byte CLASS_EXTENDS_CODE = 0x10; 47 private static final byte CLASS_TYPE_PARAMETER_BOUND_CODE = 0x12; 48 private static final byte METHOD_TYPE_PARAMETER_BOUND_CODE = 0x14; 49 private static final byte FIELD_CODE = 0x16; 50 private static final byte METHOD_RETURN_CODE = 0x18; 51 private static final byte METHOD_RECEIVER_CODE = 0x1A; 52 private static final byte METHOD_PARAMETER_CODE = 0x1C; 53 private static final byte THROWS_CODE = 0x1E; 54 private static final byte LOCAL_VARIABLE_CODE = (byte)0x80; 55 private static final byte RESOURCE_VARIABLE_CODE = (byte)0x82; 56 private static final byte EXCEPTION_PARAMETER_CODE = (byte)0x84; 57 private static final byte CAST_CODE = (byte)0x86; 58 private static final byte INSTANCEOF_CODE = (byte)0x88; 59 private static final byte NEW_CODE = (byte)0x8A; 60 private static final byte CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT_CODE = (byte)0x8C; 61 private static final byte METHOD_INVOCATION_TYPE_ARGUMENT_CODE = (byte)0x8E; 62 private static final byte LAMBDA_FORMAL_PARAMETER_CODE = (byte)0x90; 63 private static final byte METHOD_REFERENCE_TYPE_ARGUMENT_CODE = (byte)0x92; 64 65 /** 66 * Parse type annotations encoded as an array of bytes. 67 */ 68 public static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations, 69 ConstantPool cp, 70 AnnotatedElement baseDecl, 71 Class<?> container) { 72 if (rawAnnotations == null) 73 return EMPTY_TYPE_ANNOTATION_ARRAY; 74 75 ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); 76 int annotationCount = buf.getShort() & 0xFFFF; 77 List<TypeAnnotation> typeAnnotations = new ArrayList<>(annotationCount); 78 79 // Parse each TypeAnnotation 80 for (int i = 0; i < annotationCount; i++) { 81 TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, container); 82 if (ta != null) 83 typeAnnotations.add(ta); 84 } 85 86 return typeAnnotations.toArray(EMPTY_TYPE_ANNOTATION_ARRAY); 87 } 88 89 /** 90 * Parse all type annotations on the declaration supplied. 91 */ 92 public static TypeAnnotation[] parseAllTypeAnnotations(AnnotatedElement decl) { 93 Class<?> container; 94 byte[] rawBytes; 95 JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess(); 96 if (decl instanceof Class) { 97 container = (Class<?>)decl; 98 rawBytes = javaLangAccess.getRawClassTypeAnnotations(container); 99 } else if (decl instanceof Executable) { 100 container = ((Executable)decl).getDeclaringClass(); 101 rawBytes = javaLangAccess.getRawExecutableTypeAnnotations((Executable)decl); 102 } else { 103 // Should not reach here. Assert? 104 return EMPTY_TYPE_ANNOTATION_ARRAY; 105 } 106 return parseTypeAnnotations(rawBytes, javaLangAccess.getConstantPool(container), 107 decl, container); 108 } 109 110 111 private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, 112 ConstantPool cp, 113 AnnotatedElement baseDecl, 114 Class<?> container) { 115 TypeAnnotationTargetInfo ti = parseTargetInfo(buf); 116 LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf); 117 Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, false); 118 if (ti == null) // Inside a method for example 119 return null; 120 TypeAnnotation ta = new TypeAnnotation(); 121 ta.setAnnotation(a); 122 ta.setTargetInfo(ti); 123 ta.setBaseDeclaration(baseDecl); 124 ta.setLocationInfo(locationInfo); 125 return ta; 126 } 127 128 private static TypeAnnotationTargetInfo parseTargetInfo(ByteBuffer buf) { 129 byte posCode = buf.get(); 130 switch(posCode) { 131 case CAST_CODE: 132 case INSTANCEOF_CODE: 133 case NEW_CODE: { 134 short offset = buf.getShort(); 135 // CONSTRUCTORS HERE 136 } break; 137 case LOCAL_VARIABLE_CODE: 138 case RESOURCE_VARIABLE_CODE: 139 short length = buf.getShort(); 140 // probably create an array 141 for (int i = 0; i < length; ++i) { 142 short offset = buf.getShort(); 143 short varLength = buf.getShort(); 144 short index = buf.getShort(); 145 // probably add entries to an array 146 } 147 // CONSTRUCTORS HERE 148 break; 149 case EXCEPTION_PARAMETER_CODE: { 150 byte index = buf.get(); 151 // CONSTRUCTORS HERE 152 } break; 153 case METHOD_RECEIVER_CODE: 154 // no additional payload 155 return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER_TYPE); 156 case CLASS_TYPE_PARAMETER_CODE: 157 case METHOD_TYPE_PARAMETER_CODE: { 158 byte index = buf.get(); 159 TypeAnnotationTargetInfo res; 160 if (posCode == CLASS_TYPE_PARAMETER_CODE) 161 res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_TYPE_PARAMETER); 162 else 163 res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_TYPE_PARAMETER); 164 res.setCount(index); 165 return res; 166 } 167 case CLASS_TYPE_PARAMETER_BOUND_CODE: 168 case METHOD_TYPE_PARAMETER_BOUND_CODE: { 169 byte parameter_index = buf.get(); 170 byte bound_index = buf.get(); 171 TypeAnnotationTargetInfo res; 172 if (posCode == CLASS_TYPE_PARAMETER_BOUND_CODE) 173 res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_PARAMETER_BOUND); 174 else 175 res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_PARAMETER_BOUND); 176 res.setCount(parameter_index); 177 res.setSecondIndex(bound_index); 178 return res; 179 } 180 case CLASS_EXTENDS_CODE: { 181 short index = buf.getShort(); 182 // CONSTRUCTORS HERE 183 if (index == -1) { 184 return new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_EXTENDS); 185 } else if (index >= 0) { 186 TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_IMPLEMENTS); 187 res.setCount(index); 188 return res; 189 } 190 } break; 191 case THROWS_CODE: { 192 short index = buf.getShort(); 193 TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.THROWS); 194 res.setCount(index); 195 return res; 196 } 197 case METHOD_PARAMETER_CODE: { 198 byte index = buf.get(); 199 // CONSTRUCTORS HERE 200 } break; 201 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT_CODE: 202 case METHOD_INVOCATION_TYPE_ARGUMENT_CODE: 203 case METHOD_REFERENCE_TYPE_ARGUMENT_CODE: { 204 short offset = buf.getShort(); 205 byte index = buf.get(); 206 } break; 207 case METHOD_RETURN_CODE: 208 // no additional payload 209 return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN_TYPE); 210 //break; /*unreachable*/ 211 case FIELD_CODE: 212 // no additional payload 213 return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD_TYPE); 214 //break; /*unreachable*/ 215 case LAMBDA_FORMAL_PARAMETER_CODE: { 216 byte index = buf.get(); 217 // CONSTRUCTORS HERE 218 } break; 219 default: 220 // probably throw some exception 221 break; 222 } 223 return null; 224 } 225 226 // Helper 227 @SuppressWarnings({"rawtypes", "unchecked"}) 228 public static AnnotatedType[] buildAnnotatedTypes0(byte[] rawAnnotations, 229 ConstantPool cp, 230 AnnotatedElement decl, 231 Class<?> container, 232 Type[] types, 233 TypeAnnotationTarget filter) { 234 int size = types.length; 235 AnnotatedType[] result = new AnnotatedType[size]; 236 Arrays.fill(result, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE); 237 ArrayList[] l = new ArrayList[size]; // array of ArrayList<TypeAnnotation> 238 239 TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, 240 cp, 241 decl, 242 container); 243 for (TypeAnnotation t : tas) { 244 TypeAnnotationTargetInfo ti = t.getTargetInfo(); 245 if (ti.getTarget() == filter) { 246 int pos = ti.getCount(); 247 if (l[pos] == null) { 248 l[pos] = new ArrayList(); 249 } 250 l[pos].add(t); 251 } 252 } 253 for (int i = 0; i < size; i++) { 254 ArrayList<TypeAnnotation> list = l[i]; 255 if (list != null) { 256 TypeAnnotation[] typeAnnotations = list.toArray(new TypeAnnotation[0]); 257 result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i], 258 LocationInfo.BASE_LOCATION, 259 typeAnnotations, 260 typeAnnotations, 261 decl); 262 } 263 } 264 return result; 265 } 266 public static AnnotatedType buildAnnotatedType0(byte[] rawAnnotations, 267 ConstantPool cp, 268 AnnotatedElement decl, 269 Class<?> container, 270 Type type, 271 TypeAnnotationTarget filter) { 272 TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, 273 cp, 274 decl, 275 container); 276 List<TypeAnnotation> l = new ArrayList<>(); 277 for (TypeAnnotation t : tas) { 278 TypeAnnotationTargetInfo ti = t.getTargetInfo(); 279 if (ti.getTarget() == filter) 280 l.add(t); 281 } 282 TypeAnnotation[] typeAnnotations = l.toArray(new TypeAnnotation[0]); 283 return AnnotatedTypeFactory.buildAnnotatedType(type, 284 LocationInfo.BASE_LOCATION, 285 typeAnnotations, 286 typeAnnotations, 287 decl); 288 } 289 290 // Class 291 public static AnnotatedType buildAnnotatedSuperclass(byte[] rawAnnotations, 292 ConstantPool cp, 293 Class<?> decl) { 294 Type supertype = decl.getGenericSuperclass(); 295 if (supertype == null) 296 return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE; 297 return buildAnnotatedType0(rawAnnotations, 298 cp, 299 decl, 300 decl, 301 supertype, 302 TypeAnnotationTarget.CLASS_EXTENDS); 303 } 304 public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations, 305 ConstantPool cp, 306 Class<?> decl) { 307 return buildAnnotatedTypes0(rawAnnotations, 308 cp, 309 decl, 310 decl, 311 decl.getGenericInterfaces(), 312 TypeAnnotationTarget.CLASS_IMPLEMENTS); 313 } 314 315 // TypeVariable 316 public static <D extends GenericDeclaration> Annotation[] parseTypeParameterAnnotations(D genericsDecl, 317 int typeParameterIndex) { 318 AnnotatedElement decl; 319 TypeAnnotationTarget predicate; 320 if (genericsDecl instanceof Class) { 321 decl = (Class<?>)genericsDecl; 322 predicate = TypeAnnotationTarget.CLASS_TYPE_PARAMETER; 323 } else { 324 decl = (Executable)genericsDecl; 325 predicate = TypeAnnotationTarget.METHOD_TYPE_PARAMETER; 326 } 327 List<TypeAnnotation> typeVarAnnos = TypeAnnotation.filter(parseAllTypeAnnotations(decl), 328 predicate); 329 List<Annotation> res = new ArrayList<>(); 330 for (TypeAnnotation t : typeVarAnnos) 331 if (t.getTargetInfo().getCount() == typeParameterIndex) 332 res.add(t.getAnnotation()); 333 return res.toArray(new Annotation[0]); 334 } 335 336 public static <D extends GenericDeclaration> AnnotatedType[] parseAnnotatedBounds(Type[] bounds, 337 D decl, 338 int typeVarIndex) { 339 return parseAnnotatedBounds(bounds, decl, typeVarIndex, LocationInfo.BASE_LOCATION); 340 } 341 static <D extends GenericDeclaration> AnnotatedType[] parseAnnotatedBounds(Type[] bounds, 342 D decl, 343 int typeVarIndex, 344 LocationInfo loc) { 345 List<TypeAnnotation> candidates = fetchBounds(decl); 346 if (bounds != null) { 347 int startIndex = 0; 348 AnnotatedType[] res = new AnnotatedType[bounds.length]; 349 Arrays.fill(res, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE); 350 // Adjust bounds index 351 if (bounds.length > 0) { 352 Type b0 = bounds[0]; 353 if (!(b0 instanceof Class<?>)) { 354 startIndex = 1; 355 } else { 356 Class<?> c = (Class<?>)b0; 357 if (c.isInterface()) { 358 // enum? anno? 359 startIndex = 1; 360 } 361 } 362 } 363 for (int i = 0; i < bounds.length; i++) { 364 List<TypeAnnotation> l = new ArrayList<>(); 365 for (TypeAnnotation t : candidates) { 366 TypeAnnotationTargetInfo tInfo = t.getTargetInfo(); 367 if (tInfo.getSecondIndex() == i + startIndex && 368 tInfo.getCount() == typeVarIndex) { 369 l.add(t); 370 } 371 res[i] = AnnotatedTypeFactory.buildAnnotatedType(bounds[i], 372 loc, 373 l.toArray(new TypeAnnotation[0]), 374 candidates.toArray(new TypeAnnotation[0]), 375 (AnnotatedElement)decl); 376 } 377 } 378 return res; 379 } 380 return new AnnotatedType[0]; 381 } 382 383 private static <D extends GenericDeclaration> List<TypeAnnotation> fetchBounds(D decl) { 384 AnnotatedElement boundsDecl; 385 TypeAnnotationTarget target; 386 if (decl instanceof Class) { 387 target = TypeAnnotationTarget.CLASS_PARAMETER_BOUND; 388 boundsDecl = (Class)decl; 389 } else { 390 target = TypeAnnotationTarget.METHOD_PARAMETER_BOUND; 391 boundsDecl = (Executable)decl; 392 } 393 return TypeAnnotation.filter(TypeAnnotationParser.parseAllTypeAnnotations(boundsDecl), target); 394 } 395 396 private static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0]; 397 398 static Map<Class<? extends Annotation>, Annotation> mapAnnotations(TypeAnnotation[] typeAnnos) { 399 Map<Class<? extends Annotation>, Annotation> result = 400 new LinkedHashMap<Class<? extends Annotation>, Annotation>(); 401 for (TypeAnnotation t : typeAnnos) { 402 Annotation a = t.getAnnotation(); 403 Class<? extends Annotation> klass = a.annotationType(); 404 AnnotationType type = AnnotationType.getInstance(klass); 405 if (type.retention() == RetentionPolicy.RUNTIME) 406 if (result.put(klass, a) != null) 407 throw new AnnotationFormatError("Duplicate annotation for class: "+klass+": " + a); 408 } 409 return result; 410 } 411 }