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 }