Showing the changes to java/pkg/sun/reflect/annotation/AnnotationParser.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,805 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2003, 2005, 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.util.*; | ||
| 30 | import java.nio.ByteBuffer; | ||
| 31 | import java.nio.BufferUnderflowException; | ||
| 32 | import java.lang.reflect.*; | ||
| 33 | import sun.reflect.ConstantPool; | ||
| 34 | |||
| 35 | import sun.reflect.generics.parser.SignatureParser; | ||
| 36 | import sun.reflect.generics.tree.TypeSignature; | ||
| 37 | import sun.reflect.generics.factory.GenericsFactory; | ||
| 38 | import sun.reflect.generics.factory.CoreReflectionFactory; | ||
| 39 | import sun.reflect.generics.visitor.Reifier; | ||
| 40 | import sun.reflect.generics.scope.ClassScope; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * Parser for Java programming language annotations. Translates | ||
| 44 | * annotation byte streams emitted by compiler into annotation objects. | ||
| 45 | * | ||
| 46 | * @author Josh Bloch | ||
| 47 | * @since 1.5 | ||
| 48 | */ | ||
| 49 | public class AnnotationParser { | ||
| 50 | /** | ||
| 51 | * Parses the annotations described by the specified byte array. | ||
| 52 | * resolving constant references in the specified constant pool. | ||
| 53 | * The array must contain an array of annotations as described | ||
| 54 | * in the RuntimeVisibleAnnotations_attribute: | ||
| 55 | * | ||
| 56 | * u2 num_annotations; | ||
| 57 | * annotation annotations[num_annotations]; | ||
| 58 | * | ||
| 59 | * @throws AnnotationFormatError if an annotation is found to be | ||
| 60 | * malformed. | ||
| 61 | */ | ||
| 62 | public static Map<Class<? extends Annotation>, Annotation> parseAnnotations( | ||
| 63 | byte[] rawAnnotations, | ||
| 64 | ConstantPool constPool, | ||
| 65 | Class<?> container) { | ||
| 66 | if (rawAnnotations == null) | ||
| 67 | return Collections.emptyMap(); | ||
| 68 | |||
| 69 | try { | ||
| 70 | return parseAnnotations2(rawAnnotations, constPool, container); | ||
| 71 | } catch(BufferUnderflowException e) { | ||
| 72 | throw new AnnotationFormatError("Unexpected end of annotations."); | ||
| 73 | } catch(IllegalArgumentException e) { | ||
| 74 | // Type mismatch in constant pool | ||
| 75 | throw new AnnotationFormatError(e); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2( | ||
| 80 | byte[] rawAnnotations, | ||
| 81 | ConstantPool constPool, | ||
| 82 | Class<?> container) { | ||
| 83 | Map<Class<? extends Annotation>, Annotation> result = | ||
| 84 | new LinkedHashMap<Class<? extends Annotation>, Annotation>(); | ||
| 85 | ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); | ||
| 86 | int numAnnotations = buf.getShort() & 0xFFFF; | ||
| 87 | for (int i = 0; i < numAnnotations; i++) { | ||
| 88 | Annotation a = parseAnnotation(buf, constPool, container, false); | ||
| 89 | if (a != null) { | ||
| 90 | Class<? extends Annotation> klass = a.annotationType(); | ||
| 91 | AnnotationType type = AnnotationType.getInstance(klass); | ||
| 92 | if (type.retention() == RetentionPolicy.RUNTIME) | ||
| 93 | if (result.put(klass, a) != null) | ||
| 94 | throw new AnnotationFormatError( | ||
| 95 | "Duplicate annotation for class: "+klass+": " + a); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | return result; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Parses the parameter annotations described by the specified byte array. | ||
| 103 | * resolving constant references in the specified constant pool. | ||
| 104 | * The array must contain an array of annotations as described | ||
| 105 | * in the RuntimeVisibleParameterAnnotations_attribute: | ||
| 106 | * | ||
| 107 | * u1 num_parameters; | ||
| 108 | * { | ||
| 109 | * u2 num_annotations; | ||
| 110 | * annotation annotations[num_annotations]; | ||
| 111 | * } parameter_annotations[num_parameters]; | ||
| 112 | * | ||
| 113 | * Unlike parseAnnotations, rawAnnotations must not be null! | ||
| 114 | * A null value must be handled by the caller. This is so because | ||
| 115 | * we cannot determine the number of parameters if rawAnnotations | ||
| 116 | * is null. Also, the caller should check that the number | ||
| 117 | * of parameters indicated by the return value of this method | ||
| 118 | * matches the actual number of method parameters. A mismatch | ||
| 119 | * indicates that an AnnotationFormatError should be thrown. | ||
| 120 | * | ||
| 121 | * @throws AnnotationFormatError if an annotation is found to be | ||
| 122 | * malformed. | ||
| 123 | */ | ||
| 124 | public static Annotation[][] parseParameterAnnotations( | ||
| 125 | byte[] rawAnnotations, | ||
| 126 | ConstantPool constPool, | ||
| 127 | Class<?> container) { | ||
| 128 | try { | ||
| 129 | return parseParameterAnnotations2(rawAnnotations, constPool, container); | ||
| 130 | } catch(BufferUnderflowException e) { | ||
| 131 | throw new AnnotationFormatError( | ||
| 132 | "Unexpected end of parameter annotations."); | ||
| 133 | } catch(IllegalArgumentException e) { | ||
| 134 | // Type mismatch in constant pool | ||
| 135 | throw new AnnotationFormatError(e); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | private static Annotation[][] parseParameterAnnotations2( | ||
| 140 | byte[] rawAnnotations, | ||
| 141 | ConstantPool constPool, | ||
| 142 | Class<?> container) { | ||
| 143 | ByteBuffer buf = ByteBuffer.wrap(rawAnnotations); | ||
| 144 | int numParameters = buf.get() & 0xFF; | ||
| 145 | Annotation[][] result = new Annotation[numParameters][]; | ||
| 146 | |||
| 147 | for (int i = 0; i < numParameters; i++) { | ||
| 148 | int numAnnotations = buf.getShort() & 0xFFFF; | ||
| 149 | List<Annotation> annotations = | ||
| 150 | new ArrayList<Annotation>(numAnnotations); | ||
| 151 | for (int j = 0; j < numAnnotations; j++) { | ||
| 152 | Annotation a = parseAnnotation(buf, constPool, container, false); | ||
| 153 | if (a != null) { | ||
| 154 | AnnotationType type = AnnotationType.getInstance( | ||
| 155 | a.annotationType()); | ||
| 156 | if (type.retention() == RetentionPolicy.RUNTIME) | ||
| 157 | annotations.add(a); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY); | ||
| 161 | } | ||
| 162 | return result; | ||
| 163 | } | ||
| 164 | |||
| 165 | private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = | ||
| 166 | new Annotation[0]; | ||
| 167 | |||
| 168 | /** | ||
| 169 | * Parses the annotation at the current position in the specified | ||
| 170 | * byte buffer, resolving constant references in the specified constant | ||
| 171 | * pool. The cursor of the byte buffer must point to an "annotation | ||
| 172 | * structure" as described in the RuntimeVisibleAnnotations_attribute: | ||
| 173 | * | ||
| 174 | * annotation { | ||
| 175 | * u2 type_index; | ||
| 176 | * u2 num_member_value_pairs; | ||
| 177 | * { u2 member_name_index; | ||
| 178 | * member_value value; | ||
| 179 | * } member_value_pairs[num_member_value_pairs]; | ||
| 180 | * } | ||
| 181 | * } | ||
| 182 | * | ||
| 183 | * Returns the annotation, or null if the annotation's type cannot | ||
| 184 | * be found by the VM, or is not a valid annotation type. | ||
| 185 | * | ||
| 186 | * @param exceptionOnMissingAnnotationClass if true, throw | ||
| 187 | * TypeNotPresentException if a referenced annotation type is not | ||
| 188 | * available at runtime | ||
| 189 | */ | ||
| 190 | private static Annotation parseAnnotation(ByteBuffer buf, | ||
| 191 | ConstantPool constPool, | ||
| 192 | Class<?> container, | ||
| 193 | boolean exceptionOnMissingAnnotationClass) { | ||
| 194 | int typeIndex = buf.getShort() & 0xFFFF; | ||
| 195 | Class<? extends Annotation> annotationClass = null; | ||
| 196 | String sig = "[unknown]"; | ||
| 197 | try { | ||
| 198 | try { | ||
| 199 | sig = constPool.getUTF8At(typeIndex); | ||
| 200 | annotationClass = (Class<? extends Annotation>)parseSig(sig, container); | ||
| 201 | } catch (IllegalArgumentException ex) { | ||
| 202 | // support obsolete early jsr175 format class files | ||
| 203 | annotationClass = constPool.getClassAt(typeIndex); | ||
| 204 | } | ||
| 205 | } catch (NoClassDefFoundError e) { | ||
| 206 | if (exceptionOnMissingAnnotationClass) | ||
| 207 | // note: at this point sig is "[unknown]" or VM-style | ||
| 208 | // name instead of a binary name | ||
| 209 | throw new TypeNotPresentException(sig, e); | ||
| 210 | skipAnnotation(buf, false); | ||
| 211 | return null; | ||
| 212 | } | ||
| 213 | catch (TypeNotPresentException e) { | ||
| 214 | if (exceptionOnMissingAnnotationClass) | ||
| 215 | throw e; | ||
| 216 | skipAnnotation(buf, false); | ||
| 217 | return null; | ||
| 218 | } | ||
| 219 | AnnotationType type = null; | ||
| 220 | try { | ||
| 221 | type = AnnotationType.getInstance(annotationClass); | ||
| 222 | } catch (IllegalArgumentException e) { | ||
| 223 | skipAnnotation(buf, false); | ||
| 224 | return null; | ||
| 225 | } | ||
| 226 | |||
| 227 | Map<String, Class<?>> memberTypes = type.memberTypes(); | ||
| 228 | Map<String, Object> memberValues = | ||
| 229 | new LinkedHashMap<String, Object>(type.memberDefaults()); | ||
| 230 | |||
| 231 | int numMembers = buf.getShort() & 0xFFFF; | ||
| 232 | for (int i = 0; i < numMembers; i++) { | ||
| 233 | int memberNameIndex = buf.getShort() & 0xFFFF; | ||
| 234 | String memberName = constPool.getUTF8At(memberNameIndex); | ||
| 235 | Class<?> memberType = memberTypes.get(memberName); | ||
| 236 | |||
| 237 | if (memberType == null) { | ||
| 238 | // Member is no longer present in annotation type; ignore it | ||
| 239 | skipMemberValue(buf); | ||
| 240 | } else { | ||
| 241 | Object value = parseMemberValue(memberType, buf, constPool, container); | ||
| 242 | if (value instanceof AnnotationTypeMismatchExceptionProxy) | ||
| 243 | ((AnnotationTypeMismatchExceptionProxy) value). | ||
| 244 | setMember(type.members().get(memberName)); | ||
| 245 | memberValues.put(memberName, value); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | return annotationForMap(annotationClass, memberValues); | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * Returns an annotation of the given type backed by the given | ||
| 253 | * member -> value map. | ||
| 254 | */ | ||
| 255 | public static Annotation annotationForMap( | ||
| 256 | Class<? extends Annotation> type, Map<String, Object> memberValues) | ||
| 257 | { | ||
| 258 | return (Annotation) Proxy.newProxyInstance( | ||
| 259 | type.getClassLoader(), new Class[] { type }, | ||
| 260 | new AnnotationInvocationHandler(type, memberValues)); | ||
| 261 | } | ||
| 262 | |||
| 263 | /** | ||
| 264 | * Parses the annotation member value at the current position in the | ||
| 265 | * specified byte buffer, resolving constant references in the specified | ||
| 266 | * constant pool. The cursor of the byte buffer must point to a | ||
| 267 | * "member_value structure" as described in the | ||
| 268 | * RuntimeVisibleAnnotations_attribute: | ||
| 269 | * | ||
| 270 | * member_value { | ||
| 271 | * u1 tag; | ||
| 272 | * union { | ||
| 273 | * u2 const_value_index; | ||
| 274 | * { | ||
| 275 | * u2 type_name_index; | ||
| 276 | * u2 const_name_index; | ||
| 277 | * } enum_const_value; | ||
| 278 | * u2 class_info_index; | ||
| 279 | * annotation annotation_value; | ||
| 280 | * { | ||
| 281 | * u2 num_values; | ||
| 282 | * member_value values[num_values]; | ||
| 283 | * } array_value; | ||
| 284 | * } value; | ||
| 285 | * } | ||
| 286 | * | ||
| 287 | * The member must be of the indicated type. If it is not, this | ||
| 288 | * method returns an AnnotationTypeMismatchExceptionProxy. | ||
| 289 | */ | ||
| 290 | public static Object parseMemberValue(Class<?> memberType, | ||
| 291 | ByteBuffer buf, | ||
| 292 | ConstantPool constPool, | ||
| 293 | Class<?> container) { | ||
| 294 | Object result = null; | ||
| 295 | int tag = buf.get(); | ||
| 296 | switch(tag) { | ||
| 297 | case 'e': | ||
| 298 | return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container); | ||
| 299 | case 'c': | ||
| 300 | result = parseClassValue(buf, constPool, container); | ||
| 301 | break; | ||
| 302 | case '@': | ||
| 303 | result = parseAnnotation(buf, constPool, container, true); | ||
| 304 | break; | ||
| 305 | case '[': | ||
| 306 | return parseArray(memberType, buf, constPool, container); | ||
| 307 | default: | ||
| 308 | result = parseConst(tag, buf, constPool); | ||
| 309 | } | ||
| 310 | |||
| 311 | if (!(result instanceof ExceptionProxy) && | ||
| 312 | !memberType.isInstance(result)) | ||
| 313 | result = new AnnotationTypeMismatchExceptionProxy( | ||
| 314 | result.getClass() + "[" + result + "]"); | ||
| 315 | return result; | ||
| 316 | } | ||
| 317 | |||
| 318 | /** | ||
| 319 | * Parses the primitive or String annotation member value indicated by | ||
| 320 | * the specified tag byte at the current position in the specified byte | ||
| 321 | * buffer, resolving constant reference in the specified constant pool. | ||
| 322 | * The cursor of the byte buffer must point to an annotation member value | ||
| 323 | * of the type indicated by the specified tag, as described in the | ||
| 324 | * RuntimeVisibleAnnotations_attribute: | ||
| 325 | * | ||
| 326 | * u2 const_value_index; | ||
| 327 | */ | ||
| 328 | private static Object parseConst(int tag, | ||
| 329 | ByteBuffer buf, ConstantPool constPool) { | ||
| 330 | int constIndex = buf.getShort() & 0xFFFF; | ||
| 331 | switch(tag) { | ||
| 332 | case 'B': | ||
| 333 | return Byte.valueOf((byte) constPool.getIntAt(constIndex)); | ||
| 334 | case 'C': | ||
| 335 | return Character.valueOf((char) constPool.getIntAt(constIndex)); | ||
| 336 | case 'D': | ||
| 337 | return Double.valueOf(constPool.getDoubleAt(constIndex)); | ||
| 338 | case 'F': | ||
| 339 | return Float.valueOf(constPool.getFloatAt(constIndex)); | ||
| 340 | case 'I': | ||
| 341 | return Integer.valueOf(constPool.getIntAt(constIndex)); | ||
| 342 | case 'J': | ||
| 343 | return Long.valueOf(constPool.getLongAt(constIndex)); | ||
| 344 | case 'S': | ||
| 345 | return Short.valueOf((short) constPool.getIntAt(constIndex)); | ||
| 346 | case 'Z': | ||
| 347 | return Boolean.valueOf(constPool.getIntAt(constIndex) != 0); | ||
| 348 | case 's': | ||
| 349 | return constPool.getUTF8At(constIndex); | ||
| 350 | default: | ||
| 351 | throw new AnnotationFormatError( | ||
| 352 | "Invalid member-value tag in annotation: " + tag); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | /** | ||
| 357 | * Parses the Class member value at the current position in the | ||
| 358 | * specified byte buffer, resolving constant references in the specified | ||
| 359 | * constant pool. The cursor of the byte buffer must point to a "class | ||
| 360 | * info index" as described in the RuntimeVisibleAnnotations_attribute: | ||
| 361 | * | ||
| 362 | * u2 class_info_index; | ||
| 363 | */ | ||
| 364 | private static Object parseClassValue(ByteBuffer buf, | ||
| 365 | ConstantPool constPool, | ||
| 366 | Class<?> container) { | ||
| 367 | int classIndex = buf.getShort() & 0xFFFF; | ||
| 368 | try { | ||
| 369 | try { | ||
| 370 | String sig = constPool.getUTF8At(classIndex); | ||
| 371 | return parseSig(sig, container); | ||
| 372 | } catch (IllegalArgumentException ex) { | ||
| 373 | // support obsolete early jsr175 format class files | ||
| 374 | return constPool.getClassAt(classIndex); | ||
| 375 | } | ||
| 376 | } catch (NoClassDefFoundError e) { | ||
| 377 | return new TypeNotPresentExceptionProxy("[unknown]", e); | ||
| 378 | } | ||
| 379 | catch (TypeNotPresentException e) { | ||
| 380 | return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause()); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | private static Class<?> parseSig(String sig, Class<?> container) { | ||
| 385 | if (sig.equals("V")) return void.class; | ||
| 386 | SignatureParser parser = SignatureParser.make(); | ||
| 387 | TypeSignature typeSig = parser.parseTypeSig(sig); | ||
| 388 | GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container)); | ||
| 389 | Reifier reify = Reifier.make(factory); | ||
| 390 | typeSig.accept(reify); | ||
| 391 | Type result = reify.getResult(); | ||
| 392 | return toClass(result); | ||
| 393 | } | ||
| 394 | static Class<?> toClass(Type o) { | ||
| 395 | if (o instanceof GenericArrayType) | ||
| 396 | return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()), | ||
| 397 | 0) | ||
| 398 | .getClass(); | ||
| 399 | return (Class)o; | ||
| 400 | } | ||
| 401 | |||
| 402 | /** | ||
| 403 | * Parses the enum constant member value at the current position in the | ||
| 404 | * specified byte buffer, resolving constant references in the specified | ||
| 405 | * constant pool. The cursor of the byte buffer must point to a | ||
| 406 | * "enum_const_value structure" as described in the | ||
| 407 | * RuntimeVisibleAnnotations_attribute: | ||
| 408 | * | ||
| 409 | * { | ||
| 410 | * u2 type_name_index; | ||
| 411 | * u2 const_name_index; | ||
| 412 | * } enum_const_value; | ||
| 413 | */ | ||
| 414 | private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf, | ||
| 415 | ConstantPool constPool, | ||
| 416 | Class<?> container) { | ||
| 417 | int typeNameIndex = buf.getShort() & 0xFFFF; | ||
| 418 | String typeName = constPool.getUTF8At(typeNameIndex); | ||
| 419 | int constNameIndex = buf.getShort() & 0xFFFF; | ||
| 420 | String constName = constPool.getUTF8At(constNameIndex); | ||
| 421 | |||
| 422 | if (!typeName.endsWith(";")) { | ||
| 423 | // support now-obsolete early jsr175-format class files. | ||
| 424 | if (!enumType.getName().equals(typeName)) | ||
| 425 | return new AnnotationTypeMismatchExceptionProxy( | ||
| 426 | typeName + "." + constName); | ||
| 427 | } else if (enumType != parseSig(typeName, container)) { | ||
| 428 | return new AnnotationTypeMismatchExceptionProxy( | ||
| 429 | typeName + "." + constName); | ||
| 430 | } | ||
| 431 | |||
| 432 | try { | ||
| 433 | return Enum.valueOf(enumType, constName); | ||
| 434 | } catch(IllegalArgumentException e) { | ||
| 435 | return new EnumConstantNotPresentExceptionProxy( | ||
| 436 | (Class<? extends Enum>)enumType, constName); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | /** | ||
| 441 | * Parses the array value at the current position in the specified byte | ||
| 442 | * buffer, resolving constant references in the specified constant pool. | ||
| 443 | * The cursor of the byte buffer must point to an array value struct | ||
| 444 | * as specified in the RuntimeVisibleAnnotations_attribute: | ||
| 445 | * | ||
| 446 | * { | ||
| 447 | * u2 num_values; | ||
| 448 | * member_value values[num_values]; | ||
| 449 | * } array_value; | ||
| 450 | * | ||
| 451 | * If the array values do not match arrayType, an | ||
| 452 | * AnnotationTypeMismatchExceptionProxy will be returned. | ||
| 453 | */ | ||
| 454 | private static Object parseArray(Class<?> arrayType, | ||
| 455 | ByteBuffer buf, | ||
| 456 | ConstantPool constPool, | ||
| 457 | Class<?> container) { | ||
| 458 | int length = buf.getShort() & 0xFFFF; // Number of array components | ||
| 459 | Class<?> componentType = arrayType.getComponentType(); | ||
| 460 | |||
| 461 | if (componentType == byte.class) { | ||
| 462 | return parseByteArray(length, buf, constPool); | ||
| 463 | } else if (componentType == char.class) { | ||
| 464 | return parseCharArray(length, buf, constPool); | ||
| 465 | } else if (componentType == double.class) { | ||
| 466 | return parseDoubleArray(length, buf, constPool); | ||
| 467 | } else if (componentType == float.class) { | ||
| 468 | return parseFloatArray(length, buf, constPool); | ||
| 469 | } else if (componentType == int.class) { | ||
| 470 | return parseIntArray(length, buf, constPool); | ||
| 471 | } else if (componentType == long.class) { | ||
| 472 | return parseLongArray(length, buf, constPool); | ||
| 473 | } else if (componentType == short.class) { | ||
| 474 | return parseShortArray(length, buf, constPool); | ||
| 475 | } else if (componentType == boolean.class) { | ||
| 476 | return parseBooleanArray(length, buf, constPool); | ||
| 477 | } else if (componentType == String.class) { | ||
| 478 | return parseStringArray(length, buf, constPool); | ||
| 479 | } else if (componentType == Class.class) { | ||
| 480 | return parseClassArray(length, buf, constPool, container); | ||
| 481 | } else if (componentType.isEnum()) { | ||
| 482 | return parseEnumArray(length, (Class<? extends Enum>)componentType, buf, | ||
| 483 | constPool, container); | ||
| 484 | } else { | ||
| 485 | assert componentType.isAnnotation(); | ||
| 486 | return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf, | ||
| 487 | constPool, container); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | private static Object parseByteArray(int length, | ||
| 492 | ByteBuffer buf, ConstantPool constPool) { | ||
| 493 | byte[] result = new byte[length]; | ||
| 494 | boolean typeMismatch = false; | ||
| 495 | int tag = 0; | ||
| 496 | |||
| 497 | for (int i = 0; i < length; i++) { | ||
| 498 | tag = buf.get(); | ||
| 499 | if (tag == 'B') { | ||
| 500 | int index = buf.getShort() & 0xFFFF; | ||
| 501 | result[i] = (byte) constPool.getIntAt(index); | ||
| 502 | } else { | ||
| 503 | skipMemberValue(tag, buf); | ||
| 504 | typeMismatch = true; | ||
| 505 | } | ||
| 506 | } | ||
| 507 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 508 | } | ||
| 509 | |||
| 510 | private static Object parseCharArray(int length, | ||
| 511 | ByteBuffer buf, ConstantPool constPool) { | ||
| 512 | char[] result = new char[length]; | ||
| 513 | boolean typeMismatch = false; | ||
| 514 | byte tag = 0; | ||
| 515 | |||
| 516 | for (int i = 0; i < length; i++) { | ||
| 517 | tag = buf.get(); | ||
| 518 | if (tag == 'C') { | ||
| 519 | int index = buf.getShort() & 0xFFFF; | ||
| 520 | result[i] = (char) constPool.getIntAt(index); | ||
| 521 | } else { | ||
| 522 | skipMemberValue(tag, buf); | ||
| 523 | typeMismatch = true; | ||
| 524 | } | ||
| 525 | } | ||
| 526 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 527 | } | ||
| 528 | |||
| 529 | private static Object parseDoubleArray(int length, | ||
| 530 | ByteBuffer buf, ConstantPool constPool) { | ||
| 531 | double[] result = new double[length]; | ||
| 532 | boolean typeMismatch = false; | ||
| 533 | int tag = 0; | ||
| 534 | |||
| 535 | for (int i = 0; i < length; i++) { | ||
| 536 | tag = buf.get(); | ||
| 537 | if (tag == 'D') { | ||
| 538 | int index = buf.getShort() & 0xFFFF; | ||
| 539 | result[i] = constPool.getDoubleAt(index); | ||
| 540 | } else { | ||
| 541 | skipMemberValue(tag, buf); | ||
| 542 | typeMismatch = true; | ||
| 543 | } | ||
| 544 | } | ||
| 545 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 546 | } | ||
| 547 | |||
| 548 | private static Object parseFloatArray(int length, | ||
| 549 | ByteBuffer buf, ConstantPool constPool) { | ||
| 550 | float[] result = new float[length]; | ||
| 551 | boolean typeMismatch = false; | ||
| 552 | int tag = 0; | ||
| 553 | |||
| 554 | for (int i = 0; i < length; i++) { | ||
| 555 | tag = buf.get(); | ||
| 556 | if (tag == 'F') { | ||
| 557 | int index = buf.getShort() & 0xFFFF; | ||
| 558 | result[i] = constPool.getFloatAt(index); | ||
| 559 | } else { | ||
| 560 | skipMemberValue(tag, buf); | ||
| 561 | typeMismatch = true; | ||
| 562 | } | ||
| 563 | } | ||
| 564 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 565 | } | ||
| 566 | |||
| 567 | private static Object parseIntArray(int length, | ||
| 568 | ByteBuffer buf, ConstantPool constPool) { | ||
| 569 | int[] result = new int[length]; | ||
| 570 | boolean typeMismatch = false; | ||
| 571 | int tag = 0; | ||
| 572 | |||
| 573 | for (int i = 0; i < length; i++) { | ||
| 574 | tag = buf.get(); | ||
| 575 | if (tag == 'I') { | ||
| 576 | int index = buf.getShort() & 0xFFFF; | ||
| 577 | result[i] = constPool.getIntAt(index); | ||
| 578 | } else { | ||
| 579 | skipMemberValue(tag, buf); | ||
| 580 | typeMismatch = true; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 584 | } | ||
| 585 | |||
| 586 | private static Object parseLongArray(int length, | ||
| 587 | ByteBuffer buf, ConstantPool constPool) { | ||
| 588 | long[] result = new long[length]; | ||
| 589 | boolean typeMismatch = false; | ||
| 590 | int tag = 0; | ||
| 591 | |||
| 592 | for (int i = 0; i < length; i++) { | ||
| 593 | tag = buf.get(); | ||
| 594 | if (tag == 'J') { | ||
| 595 | int index = buf.getShort() & 0xFFFF; | ||
| 596 | result[i] = constPool.getLongAt(index); | ||
| 597 | } else { | ||
| 598 | skipMemberValue(tag, buf); | ||
| 599 | typeMismatch = true; | ||
| 600 | } | ||
| 601 | } | ||
| 602 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 603 | } | ||
| 604 | |||
| 605 | private static Object parseShortArray(int length, | ||
| 606 | ByteBuffer buf, ConstantPool constPool) { | ||
| 607 | short[] result = new short[length]; | ||
| 608 | boolean typeMismatch = false; | ||
| 609 | int tag = 0; | ||
| 610 | |||
| 611 | for (int i = 0; i < length; i++) { | ||
| 612 | tag = buf.get(); | ||
| 613 | if (tag == 'S') { | ||
| 614 | int index = buf.getShort() & 0xFFFF; | ||
| 615 | result[i] = (short) constPool.getIntAt(index); | ||
| 616 | } else { | ||
| 617 | skipMemberValue(tag, buf); | ||
| 618 | typeMismatch = true; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 622 | } | ||
| 623 | |||
| 624 | private static Object parseBooleanArray(int length, | ||
| 625 | ByteBuffer buf, ConstantPool constPool) { | ||
| 626 | boolean[] result = new boolean[length]; | ||
| 627 | boolean typeMismatch = false; | ||
| 628 | int tag = 0; | ||
| 629 | |||
| 630 | for (int i = 0; i < length; i++) { | ||
| 631 | tag = buf.get(); | ||
| 632 | if (tag == 'Z') { | ||
| 633 | int index = buf.getShort() & 0xFFFF; | ||
| 634 | result[i] = (constPool.getIntAt(index) != 0); | ||
| 635 | } else { | ||
| 636 | skipMemberValue(tag, buf); | ||
| 637 | typeMismatch = true; | ||
| 638 | } | ||
| 639 | } | ||
| 640 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 641 | } | ||
| 642 | |||
| 643 | private static Object parseStringArray(int length, | ||
| 644 | ByteBuffer buf, ConstantPool constPool) { | ||
| 645 | String[] result = new String[length]; | ||
| 646 | boolean typeMismatch = false; | ||
| 647 | int tag = 0; | ||
| 648 | |||
| 649 | for (int i = 0; i < length; i++) { | ||
| 650 | tag = buf.get(); | ||
| 651 | if (tag == 's') { | ||
| 652 | int index = buf.getShort() & 0xFFFF; | ||
| 653 | result[i] = constPool.getUTF8At(index); | ||
| 654 | } else { | ||
| 655 | skipMemberValue(tag, buf); | ||
| 656 | typeMismatch = true; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 660 | } | ||
| 661 | |||
| 662 | private static Object parseClassArray(int length, | ||
| 663 | ByteBuffer buf, | ||
| 664 | ConstantPool constPool, | ||
| 665 | Class<?> container) { | ||
| 666 | Object[] result = new Class<?>[length]; | ||
| 667 | boolean typeMismatch = false; | ||
| 668 | int tag = 0; | ||
| 669 | |||
| 670 | for (int i = 0; i < length; i++) { | ||
| 671 | tag = buf.get(); | ||
| 672 | if (tag == 'c') { | ||
| 673 | result[i] = parseClassValue(buf, constPool, container); | ||
| 674 | } else { | ||
| 675 | skipMemberValue(tag, buf); | ||
| 676 | typeMismatch = true; | ||
| 677 | } | ||
| 678 | } | ||
| 679 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 680 | } | ||
| 681 | |||
| 682 | private static Object parseEnumArray(int length, Class<? extends Enum> enumType, | ||
| 683 | ByteBuffer buf, | ||
| 684 | ConstantPool constPool, | ||
| 685 | Class<?> container) { | ||
| 686 | Object[] result = (Object[]) Array.newInstance(enumType, length); | ||
| 687 | boolean typeMismatch = false; | ||
| 688 | int tag = 0; | ||
| 689 | |||
| 690 | for (int i = 0; i < length; i++) { | ||
| 691 | tag = buf.get(); | ||
| 692 | if (tag == 'e') { | ||
| 693 | result[i] = parseEnumValue(enumType, buf, constPool, container); | ||
| 694 | } else { | ||
| 695 | skipMemberValue(tag, buf); | ||
| 696 | typeMismatch = true; | ||
| 697 | } | ||
| 698 | } | ||
| 699 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 700 | } | ||
| 701 | |||
| 702 | private static Object parseAnnotationArray(int length, | ||
| 703 | Class<? extends Annotation> annotationType, | ||
| 704 | ByteBuffer buf, | ||
| 705 | ConstantPool constPool, | ||
| 706 | Class<?> container) { | ||
| 707 | Object[] result = (Object[]) Array.newInstance(annotationType, length); | ||
| 708 | boolean typeMismatch = false; | ||
| 709 | int tag = 0; | ||
| 710 | |||
| 711 | for (int i = 0; i < length; i++) { | ||
| 712 | tag = buf.get(); | ||
| 713 | if (tag == '@') { | ||
| 714 | result[i] = parseAnnotation(buf, constPool, container, true); | ||
| 715 | } else { | ||
| 716 | skipMemberValue(tag, buf); | ||
| 717 | typeMismatch = true; | ||
| 718 | } | ||
| 719 | } | ||
| 720 | return typeMismatch ? exceptionProxy(tag) : result; | ||
| 721 | } | ||
| 722 | |||
| 723 | /** | ||
| 724 | * Return an appropriate exception proxy for a mismatching array | ||
| 725 | * annotation where the erroneous array has the specified tag. | ||
| 726 | */ | ||
| 727 | private static ExceptionProxy exceptionProxy(int tag) { | ||
| 728 | return new AnnotationTypeMismatchExceptionProxy( | ||
| 729 | "Array with component tag: " + tag); | ||
| 730 | } | ||
| 731 | |||
| 732 | /** | ||
| 733 | * Skips the annotation at the current position in the specified | ||
| 734 | * byte buffer. The cursor of the byte buffer must point to | ||
| 735 | * an "annotation structure" OR two bytes into an annotation | ||
| 736 | * structure (i.e., after the type index). | ||
| 737 | * | ||
| 738 | * @parameter complete true if the byte buffer points to the beginning | ||
| 739 | * of an annotation structure (rather than two bytes in). | ||
| 740 | */ | ||
| 741 | private static void skipAnnotation(ByteBuffer buf, boolean complete) { | ||
| 742 | if (complete) | ||
| 743 | buf.getShort(); // Skip type index | ||
| 744 | int numMembers = buf.getShort() & 0xFFFF; | ||
| 745 | for (int i = 0; i < numMembers; i++) { | ||
| 746 | buf.getShort(); // Skip memberNameIndex | ||
| 747 | skipMemberValue(buf); | ||
| 748 | } | ||
| 749 | } | ||
| 750 | |||
| 751 | /** | ||
| 752 | * Skips the annotation member value at the current position in the | ||
| 753 | * specified byte buffer. The cursor of the byte buffer must point to a | ||
| 754 | * "member_value structure." | ||
| 755 | */ | ||
| 756 | private static void skipMemberValue(ByteBuffer buf) { | ||
| 757 | int tag = buf.get(); | ||
| 758 | skipMemberValue(tag, buf); | ||
| 759 | } | ||
| 760 | |||
| 761 | /** | ||
| 762 | * Skips the annotation member value at the current position in the | ||
| 763 | * specified byte buffer. The cursor of the byte buffer must point | ||
| 764 | * immediately after the tag in a "member_value structure." | ||
| 765 | */ | ||
| 766 | private static void skipMemberValue(int tag, ByteBuffer buf) { | ||
| 767 | switch(tag) { | ||
| 768 | case 'e': // Enum value | ||
| 769 | buf.getInt(); // (Two shorts, actually.) | ||
| 770 | break; | ||
| 771 | case '@': | ||
| 772 | skipAnnotation(buf, true); | ||
| 773 | break; | ||
| 774 | case '[': | ||
| 775 | skipArray(buf); | ||
| 776 | break; | ||
| 777 | default: | ||
| 778 | // Class, primitive, or String | ||
| 779 | buf.getShort(); | ||
| 780 | } | ||
| 781 | } | ||
| 782 | |||
| 783 | /** | ||
| 784 | * Skips the array value at the current position in the specified byte | ||
| 785 | * buffer. The cursor of the byte buffer must point to an array value | ||
| 786 | * struct. | ||
| 787 | */ | ||
| 788 | private static void skipArray(ByteBuffer buf) { | ||
| 789 | int length = buf.getShort() & 0xFFFF; | ||
| 790 | for (int i = 0; i < length; i++) | ||
| 791 | skipMemberValue(buf); | ||
| 792 | } | ||
| 793 | |||
| 794 | /* | ||
| 795 | * This method converts the annotation map returned by the parseAnnotations() | ||
| 796 | * method to an array. It is called by Field.getDeclaredAnnotations(), | ||
| 797 | * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations(). | ||
| 798 | * This avoids the reflection classes to load the Annotation class until | ||
| 799 | * it is needed. | ||
| 800 | */ | ||
| 801 | private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; | ||
| 802 | public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) { | ||
| 803 | return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY); | ||
| 804 | } | ||
| 805 | } | ||