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 }