blob: 5a5f5b5cb51961b2ee54c74ba0f5b62ce7843285 [file] [log] [blame]
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.reflect.annotation;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
import java.lang.reflect.AnnotatedElement;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* A TypeAnnotation contains all the information needed to transform type
* annotations on declarations in the class file to actual Annotations in
* AnnotatedType instances.
*
* TypeAnnotaions contain a base Annotation, location info (which lets you
* distinguish between '@A Inner.@B Outer' in for example nested types),
* target info and the declaration the TypeAnnotaiton was parsed from.
*/
public final class TypeAnnotation {
private final TypeAnnotationTargetInfo targetInfo;
private final LocationInfo loc;
private final Annotation annotation;
private final AnnotatedElement baseDeclaration;
public TypeAnnotation(TypeAnnotationTargetInfo targetInfo,
LocationInfo loc,
Annotation annotation,
AnnotatedElement baseDeclaration) {
this.targetInfo = targetInfo;
this.loc = loc;
this.annotation = annotation;
this.baseDeclaration = baseDeclaration;
}
public TypeAnnotationTargetInfo getTargetInfo() {
return targetInfo;
}
public Annotation getAnnotation() {
return annotation;
}
public AnnotatedElement getBaseDeclaration() {
return baseDeclaration;
}
public LocationInfo getLocationInfo() {
return loc;
}
public static List<TypeAnnotation> filter(TypeAnnotation[] typeAnnotations,
TypeAnnotationTarget predicate) {
ArrayList<TypeAnnotation> typeAnnos = new ArrayList<>(typeAnnotations.length);
for (TypeAnnotation t : typeAnnotations)
if (t.getTargetInfo().getTarget() == predicate)
typeAnnos.add(t);
typeAnnos.trimToSize();
return typeAnnos;
}
public static enum TypeAnnotationTarget {
CLASS_TYPE_PARAMETER,
METHOD_TYPE_PARAMETER,
CLASS_EXTENDS,
CLASS_IMPLEMENTS, // Not in the spec
CLASS_TYPE_PARAMETER_BOUND,
METHOD_TYPE_PARAMETER_BOUND,
FIELD,
METHOD_RETURN,
METHOD_RECEIVER,
METHOD_FORMAL_PARAMETER,
THROWS;
}
public static final class TypeAnnotationTargetInfo {
private final TypeAnnotationTarget target;
private final int count;
private final int secondaryIndex;
private static final int UNUSED_INDEX = -2; // this is not a valid index in the 308 spec
public TypeAnnotationTargetInfo(TypeAnnotationTarget target) {
this(target, UNUSED_INDEX, UNUSED_INDEX);
}
public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
int count) {
this(target, count, UNUSED_INDEX);
}
public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
int count,
int secondaryIndex) {
this.target = target;
this.count = count;
this.secondaryIndex = secondaryIndex;
}
public TypeAnnotationTarget getTarget() {
return target;
}
public int getCount() {
return count;
}
public int getSecondaryIndex() {
return secondaryIndex;
}
@Override
public String toString() {
return "" + target + ": " + count + ", " + secondaryIndex;
}
}
public static final class LocationInfo {
private final int depth;
private final Location[] locations;
private LocationInfo() {
this(0, new Location[0]);
}
private LocationInfo(int depth, Location[] locations) {
this.depth = depth;
this.locations = locations;
}
public static final LocationInfo BASE_LOCATION = new LocationInfo();
public static LocationInfo parseLocationInfo(ByteBuffer buf) {
int depth = buf.get() & 0xFF;
if (depth == 0)
return BASE_LOCATION;
Location[] locations = new Location[depth];
for (int i = 0; i < depth; i++) {
byte tag = buf.get();
short index = (short)(buf.get() & 0xFF);
if (!(tag == 0 || tag == 1 | tag == 2 || tag == 3))
throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
if (tag != 3 && index != 0)
throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
locations[i] = new Location(tag, index);
}
return new LocationInfo(depth, locations);
}
public LocationInfo pushArray() {
return pushLocation((byte)0, (short)0);
}
public LocationInfo pushInner() {
return pushLocation((byte)1, (short)0);
}
public LocationInfo pushWildcard() {
return pushLocation((byte) 2, (short) 0);
}
public LocationInfo pushTypeArg(short index) {
return pushLocation((byte) 3, index);
}
public LocationInfo pushLocation(byte tag, short index) {
int newDepth = this.depth + 1;
Location[] res = new Location[newDepth];
System.arraycopy(this.locations, 0, res, 0, depth);
res[newDepth - 1] = new Location(tag, (short)(index & 0xFF));
return new LocationInfo(newDepth, res);
}
/** Pop a series of locations matching {@code tag}. Stop poping as soon as a non-matching tag is found. */
public LocationInfo popAllLocations(byte tag) {
LocationInfo l = this;
int newDepth = l.depth;
while(newDepth > 0 && l.locations[newDepth - 1].tag == tag) {
newDepth--;
}
if (newDepth != l.depth) {
Location[] res = new Location[newDepth];
System.arraycopy(this.locations, 0, res, 0, newDepth);
return new LocationInfo(newDepth, res);
} else
return l;
}
public TypeAnnotation[] filter(TypeAnnotation[] ta) {
ArrayList<TypeAnnotation> l = new ArrayList<>(ta.length);
for (TypeAnnotation t : ta) {
if (isSameLocationInfo(t.getLocationInfo()))
l.add(t);
}
return l.toArray(AnnotatedTypeFactory.EMPTY_TYPE_ANNOTATION_ARRAY);
}
boolean isSameLocationInfo(LocationInfo other) {
if (depth != other.depth)
return false;
for (int i = 0; i < depth; i++)
if (!locations[i].isSameLocation(other.locations[i]))
return false;
return true;
}
public static final class Location {
public final byte tag;
public final short index;
boolean isSameLocation(Location other) {
return tag == other.tag && index == other.index;
}
public Location(byte tag, short index) {
this.tag = tag;
this.index = index;
}
}
}
@Override
public String toString() {
return annotation.toString() + " with Targetnfo: " +
targetInfo.toString() + " on base declaration: " +
baseDeclaration.toString();
}
}