feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
319
jdkSrc/jdk8/sun/reflect/annotation/AnnotatedTypeFactory.java
Normal file
319
jdkSrc/jdk8/sun/reflect/annotation/AnnotatedTypeFactory.java
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static sun.reflect.annotation.TypeAnnotation.*;
|
||||
|
||||
public final class AnnotatedTypeFactory {
|
||||
/**
|
||||
* Create an AnnotatedType.
|
||||
*
|
||||
* @param type the type this AnnotatedType corresponds to
|
||||
* @param currentLoc the location this AnnotatedType corresponds to
|
||||
* @param actualTypeAnnos the type annotations this AnnotatedType has
|
||||
* @param allOnSameTarget all type annotation on the same TypeAnnotationTarget
|
||||
* as the AnnotatedType being built
|
||||
* @param decl the declaration having the type use this AnnotatedType
|
||||
* corresponds to
|
||||
*/
|
||||
public static AnnotatedType buildAnnotatedType(Type type,
|
||||
LocationInfo currentLoc,
|
||||
TypeAnnotation[] actualTypeAnnos,
|
||||
TypeAnnotation[] allOnSameTarget,
|
||||
AnnotatedElement decl) {
|
||||
if (type == null) {
|
||||
return EMPTY_ANNOTATED_TYPE;
|
||||
}
|
||||
if (isArray(type))
|
||||
return new AnnotatedArrayTypeImpl(type,
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
if (type instanceof Class) {
|
||||
return new AnnotatedTypeBaseImpl(type,
|
||||
addNesting(type, currentLoc),
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
} else if (type instanceof TypeVariable) {
|
||||
return new AnnotatedTypeVariableImpl((TypeVariable)type,
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
|
||||
addNesting(type, currentLoc),
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
} else if (type instanceof WildcardType) {
|
||||
return new AnnotatedWildcardTypeImpl((WildcardType) type,
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
}
|
||||
throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
|
||||
}
|
||||
|
||||
private static LocationInfo addNesting(Type type, LocationInfo addTo) {
|
||||
if (isArray(type))
|
||||
return addTo;
|
||||
if (type instanceof Class) {
|
||||
Class<?> clz = (Class)type;
|
||||
if (clz.getEnclosingClass() == null)
|
||||
return addTo;
|
||||
if (Modifier.isStatic(clz.getModifiers()))
|
||||
return addNesting(clz.getEnclosingClass(), addTo);
|
||||
return addNesting(clz.getEnclosingClass(), addTo.pushInner());
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType t = (ParameterizedType)type;
|
||||
if (t.getOwnerType() == null)
|
||||
return addTo;
|
||||
return addNesting(t.getOwnerType(), addTo.pushInner());
|
||||
}
|
||||
return addTo;
|
||||
}
|
||||
|
||||
private static boolean isArray(Type t) {
|
||||
if (t instanceof Class) {
|
||||
Class<?> c = (Class)t;
|
||||
if (c.isArray())
|
||||
return true;
|
||||
} else if (t instanceof GenericArrayType) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
|
||||
new TypeAnnotation[0], new TypeAnnotation[0], null);
|
||||
static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
|
||||
|
||||
private static class AnnotatedTypeBaseImpl implements AnnotatedType {
|
||||
private final Type type;
|
||||
private final AnnotatedElement decl;
|
||||
private final LocationInfo location;
|
||||
private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
|
||||
private final Map<Class <? extends Annotation>, Annotation> annotations;
|
||||
|
||||
AnnotatedTypeBaseImpl(Type type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
this.type = type;
|
||||
this.decl = decl;
|
||||
this.location = location;
|
||||
this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
|
||||
this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations));
|
||||
}
|
||||
|
||||
// AnnotatedElement
|
||||
@Override
|
||||
public final Annotation[] getAnnotations() {
|
||||
return getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
|
||||
return getDeclaredAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Annotation> T[] getAnnotationsByType(Class<T> annotation) {
|
||||
return getDeclaredAnnotationsByType(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Annotation[] getDeclaredAnnotations() {
|
||||
return annotations.values().toArray(new Annotation[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
|
||||
return (T)annotations.get(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotation) {
|
||||
return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotations, annotation);
|
||||
}
|
||||
|
||||
// AnnotatedType
|
||||
@Override
|
||||
public final Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
// Implementation details
|
||||
final LocationInfo getLocation() {
|
||||
return location;
|
||||
}
|
||||
final TypeAnnotation[] getTypeAnnotations() {
|
||||
return allOnSameTargetTypeAnnotations;
|
||||
}
|
||||
final AnnotatedElement getDecl() {
|
||||
return decl;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
|
||||
AnnotatedArrayTypeImpl(Type type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedGenericComponentType() {
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
|
||||
getLocation().pushArray(),
|
||||
getTypeAnnotations(),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
|
||||
private Type getComponentType() {
|
||||
Type t = getType();
|
||||
if (t instanceof Class) {
|
||||
Class<?> c = (Class)t;
|
||||
return c.getComponentType();
|
||||
}
|
||||
return ((GenericArrayType)t).getGenericComponentType();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
|
||||
AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedBounds() {
|
||||
return getTypeVariable().getAnnotatedBounds();
|
||||
}
|
||||
|
||||
private TypeVariable<?> getTypeVariable() {
|
||||
return (TypeVariable)getType();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl
|
||||
implements AnnotatedParameterizedType {
|
||||
AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedActualTypeArguments() {
|
||||
Type[] arguments = getParameterizedType().getActualTypeArguments();
|
||||
AnnotatedType[] res = new AnnotatedType[arguments.length];
|
||||
Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
|
||||
int initialCapacity = getTypeAnnotations().length;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
|
||||
LocationInfo newLoc = getLocation().pushTypeArg((byte)i);
|
||||
for (TypeAnnotation t : getTypeAnnotations())
|
||||
if (t.getLocationInfo().isSameLocationInfo(newLoc))
|
||||
l.add(t);
|
||||
res[i] = buildAnnotatedType(arguments[i],
|
||||
newLoc,
|
||||
l.toArray(new TypeAnnotation[0]),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private ParameterizedType getParameterizedType() {
|
||||
return (ParameterizedType)getType();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
|
||||
private final boolean hasUpperBounds;
|
||||
AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
hasUpperBounds = (type.getLowerBounds().length == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedUpperBounds() {
|
||||
if (!hasUpperBounds())
|
||||
return new AnnotatedType[0];
|
||||
return getAnnotatedBounds(getWildcardType().getUpperBounds());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedLowerBounds() {
|
||||
if (hasUpperBounds)
|
||||
return new AnnotatedType[0];
|
||||
return getAnnotatedBounds(getWildcardType().getLowerBounds());
|
||||
}
|
||||
|
||||
private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
|
||||
AnnotatedType[] res = new AnnotatedType[bounds.length];
|
||||
Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
|
||||
LocationInfo newLoc = getLocation().pushWildcard();
|
||||
int initialCapacity = getTypeAnnotations().length;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
|
||||
for (TypeAnnotation t : getTypeAnnotations())
|
||||
if (t.getLocationInfo().isSameLocationInfo(newLoc))
|
||||
l.add(t);
|
||||
res[i] = buildAnnotatedType(bounds[i],
|
||||
newLoc,
|
||||
l.toArray(new TypeAnnotation[0]),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private WildcardType getWildcardType() {
|
||||
return (WildcardType)getType();
|
||||
}
|
||||
|
||||
private boolean hasUpperBounds() {
|
||||
return hasUpperBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2014, 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.io.ObjectInputStream;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* InvocationHandler for dynamic proxy implementation of Annotation.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
|
||||
private static final long serialVersionUID = 6182022883658399397L;
|
||||
private final Class<? extends Annotation> type;
|
||||
private final Map<String, Object> memberValues;
|
||||
|
||||
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
|
||||
Class<?>[] superInterfaces = type.getInterfaces();
|
||||
if (!type.isAnnotation() ||
|
||||
superInterfaces.length != 1 ||
|
||||
superInterfaces[0] != java.lang.annotation.Annotation.class)
|
||||
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
|
||||
this.type = type;
|
||||
this.memberValues = memberValues;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
String member = method.getName();
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
|
||||
// Handle Object and Annotation methods
|
||||
if (member.equals("equals") && paramTypes.length == 1 &&
|
||||
paramTypes[0] == Object.class)
|
||||
return equalsImpl(args[0]);
|
||||
if (paramTypes.length != 0)
|
||||
throw new AssertionError("Too many parameters for an annotation method");
|
||||
|
||||
switch(member) {
|
||||
case "toString":
|
||||
return toStringImpl();
|
||||
case "hashCode":
|
||||
return hashCodeImpl();
|
||||
case "annotationType":
|
||||
return type;
|
||||
}
|
||||
|
||||
// Handle annotation member accessors
|
||||
Object result = memberValues.get(member);
|
||||
|
||||
if (result == null)
|
||||
throw new IncompleteAnnotationException(type, member);
|
||||
|
||||
if (result instanceof ExceptionProxy)
|
||||
throw ((ExceptionProxy) result).generateException();
|
||||
|
||||
if (result.getClass().isArray() && Array.getLength(result) != 0)
|
||||
result = cloneArray(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method, which clones its array argument, would not be necessary
|
||||
* if Cloneable had a public clone method.
|
||||
*/
|
||||
private Object cloneArray(Object array) {
|
||||
Class<?> type = array.getClass();
|
||||
|
||||
if (type == byte[].class) {
|
||||
byte[] byteArray = (byte[])array;
|
||||
return byteArray.clone();
|
||||
}
|
||||
if (type == char[].class) {
|
||||
char[] charArray = (char[])array;
|
||||
return charArray.clone();
|
||||
}
|
||||
if (type == double[].class) {
|
||||
double[] doubleArray = (double[])array;
|
||||
return doubleArray.clone();
|
||||
}
|
||||
if (type == float[].class) {
|
||||
float[] floatArray = (float[])array;
|
||||
return floatArray.clone();
|
||||
}
|
||||
if (type == int[].class) {
|
||||
int[] intArray = (int[])array;
|
||||
return intArray.clone();
|
||||
}
|
||||
if (type == long[].class) {
|
||||
long[] longArray = (long[])array;
|
||||
return longArray.clone();
|
||||
}
|
||||
if (type == short[].class) {
|
||||
short[] shortArray = (short[])array;
|
||||
return shortArray.clone();
|
||||
}
|
||||
if (type == boolean[].class) {
|
||||
boolean[] booleanArray = (boolean[])array;
|
||||
return booleanArray.clone();
|
||||
}
|
||||
|
||||
Object[] objectArray = (Object[])array;
|
||||
return objectArray.clone();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of dynamicProxy.toString()
|
||||
*/
|
||||
private String toStringImpl() {
|
||||
StringBuilder result = new StringBuilder(128);
|
||||
result.append('@');
|
||||
result.append(type.getName());
|
||||
result.append('(');
|
||||
boolean firstMember = true;
|
||||
for (Map.Entry<String, Object> e : memberValues.entrySet()) {
|
||||
if (firstMember)
|
||||
firstMember = false;
|
||||
else
|
||||
result.append(", ");
|
||||
|
||||
result.append(e.getKey());
|
||||
result.append('=');
|
||||
result.append(memberValueToString(e.getValue()));
|
||||
}
|
||||
result.append(')');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a member value (in "dynamic proxy return form") into a string
|
||||
*/
|
||||
private static String memberValueToString(Object value) {
|
||||
Class<?> type = value.getClass();
|
||||
if (!type.isArray()) // primitive, string, class, enum const,
|
||||
// or annotation
|
||||
return value.toString();
|
||||
|
||||
if (type == byte[].class)
|
||||
return Arrays.toString((byte[]) value);
|
||||
if (type == char[].class)
|
||||
return Arrays.toString((char[]) value);
|
||||
if (type == double[].class)
|
||||
return Arrays.toString((double[]) value);
|
||||
if (type == float[].class)
|
||||
return Arrays.toString((float[]) value);
|
||||
if (type == int[].class)
|
||||
return Arrays.toString((int[]) value);
|
||||
if (type == long[].class)
|
||||
return Arrays.toString((long[]) value);
|
||||
if (type == short[].class)
|
||||
return Arrays.toString((short[]) value);
|
||||
if (type == boolean[].class)
|
||||
return Arrays.toString((boolean[]) value);
|
||||
return Arrays.toString((Object[]) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dynamicProxy.equals(Object o)
|
||||
*/
|
||||
private Boolean equalsImpl(Object o) {
|
||||
if (o == this)
|
||||
return true;
|
||||
|
||||
if (!type.isInstance(o))
|
||||
return false;
|
||||
for (Method memberMethod : getMemberMethods()) {
|
||||
String member = memberMethod.getName();
|
||||
Object ourValue = memberValues.get(member);
|
||||
Object hisValue = null;
|
||||
AnnotationInvocationHandler hisHandler = asOneOfUs(o);
|
||||
if (hisHandler != null) {
|
||||
hisValue = hisHandler.memberValues.get(member);
|
||||
} else {
|
||||
try {
|
||||
hisValue = memberMethod.invoke(o);
|
||||
} catch (InvocationTargetException e) {
|
||||
return false;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
if (!memberValueEquals(ourValue, hisValue))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object's invocation handler if that object is a dynamic
|
||||
* proxy with a handler of type AnnotationInvocationHandler.
|
||||
* Returns null otherwise.
|
||||
*/
|
||||
private AnnotationInvocationHandler asOneOfUs(Object o) {
|
||||
if (Proxy.isProxyClass(o.getClass())) {
|
||||
InvocationHandler handler = Proxy.getInvocationHandler(o);
|
||||
if (handler instanceof AnnotationInvocationHandler)
|
||||
return (AnnotationInvocationHandler) handler;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the two member values in "dynamic proxy return form"
|
||||
* are equal using the appropriate equality function depending on the
|
||||
* member type. The two values will be of the same type unless one of
|
||||
* the containing annotations is ill-formed. If one of the containing
|
||||
* annotations is ill-formed, this method will return false unless the
|
||||
* two members are identical object references.
|
||||
*/
|
||||
private static boolean memberValueEquals(Object v1, Object v2) {
|
||||
Class<?> type = v1.getClass();
|
||||
|
||||
// Check for primitive, string, class, enum const, annotation,
|
||||
// or ExceptionProxy
|
||||
if (!type.isArray())
|
||||
return v1.equals(v2);
|
||||
|
||||
// Check for array of string, class, enum const, annotation,
|
||||
// or ExceptionProxy
|
||||
if (v1 instanceof Object[] && v2 instanceof Object[])
|
||||
return Arrays.equals((Object[]) v1, (Object[]) v2);
|
||||
|
||||
// Check for ill formed annotation(s)
|
||||
if (v2.getClass() != type)
|
||||
return false;
|
||||
|
||||
// Deal with array of primitives
|
||||
if (type == byte[].class)
|
||||
return Arrays.equals((byte[]) v1, (byte[]) v2);
|
||||
if (type == char[].class)
|
||||
return Arrays.equals((char[]) v1, (char[]) v2);
|
||||
if (type == double[].class)
|
||||
return Arrays.equals((double[]) v1, (double[]) v2);
|
||||
if (type == float[].class)
|
||||
return Arrays.equals((float[]) v1, (float[]) v2);
|
||||
if (type == int[].class)
|
||||
return Arrays.equals((int[]) v1, (int[]) v2);
|
||||
if (type == long[].class)
|
||||
return Arrays.equals((long[]) v1, (long[]) v2);
|
||||
if (type == short[].class)
|
||||
return Arrays.equals((short[]) v1, (short[]) v2);
|
||||
assert type == boolean[].class;
|
||||
return Arrays.equals((boolean[]) v1, (boolean[]) v2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the member methods for our annotation type. These are
|
||||
* obtained lazily and cached, as they're expensive to obtain
|
||||
* and we only need them if our equals method is invoked (which should
|
||||
* be rare).
|
||||
*/
|
||||
private Method[] getMemberMethods() {
|
||||
if (memberMethods == null) {
|
||||
memberMethods = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Method[]>() {
|
||||
public Method[] run() {
|
||||
final Method[] mm = type.getDeclaredMethods();
|
||||
validateAnnotationMethods(mm);
|
||||
AccessibleObject.setAccessible(mm, true);
|
||||
return mm;
|
||||
}
|
||||
});
|
||||
}
|
||||
return memberMethods;
|
||||
}
|
||||
private transient volatile Method[] memberMethods = null;
|
||||
|
||||
/**
|
||||
* Validates that a method is structurally appropriate for an
|
||||
* annotation type. As of Java SE 8, annotation types cannot
|
||||
* contain static methods and the declared methods of an
|
||||
* annotation type must take zero arguments and there are
|
||||
* restrictions on the return type.
|
||||
*/
|
||||
private void validateAnnotationMethods(Method[] memberMethods) {
|
||||
/*
|
||||
* Specification citations below are from JLS
|
||||
* 9.6.1. Annotation Type Elements
|
||||
*/
|
||||
boolean valid = true;
|
||||
for(Method method : memberMethods) {
|
||||
/*
|
||||
* "By virtue of the AnnotationTypeElementDeclaration
|
||||
* production, a method declaration in an annotation type
|
||||
* declaration cannot have formal parameters, type
|
||||
* parameters, or a throws clause.
|
||||
*
|
||||
* "By virtue of the AnnotationTypeElementModifier
|
||||
* production, a method declaration in an annotation type
|
||||
* declaration cannot be default or static."
|
||||
*/
|
||||
if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) ||
|
||||
method.isDefault() ||
|
||||
method.getParameterCount() != 0 ||
|
||||
method.getExceptionTypes().length != 0) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* "It is a compile-time error if the return type of a
|
||||
* method declared in an annotation type is not one of the
|
||||
* following: a primitive type, String, Class, any
|
||||
* parameterized invocation of Class, an enum type
|
||||
* (section 8.9), an annotation type, or an array type
|
||||
* (chapter 10) whose element type is one of the preceding
|
||||
* types."
|
||||
*/
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (returnType.isArray()) {
|
||||
returnType = returnType.getComponentType();
|
||||
if (returnType.isArray()) { // Only single dimensional arrays
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!((returnType.isPrimitive() && returnType != void.class) ||
|
||||
returnType == java.lang.String.class ||
|
||||
returnType == java.lang.Class.class ||
|
||||
returnType.isEnum() ||
|
||||
returnType.isAnnotation())) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* "It is a compile-time error if any method declared in an
|
||||
* annotation type has a signature that is
|
||||
* override-equivalent to that of any public or protected
|
||||
* method declared in class Object or in the interface
|
||||
* java.lang.annotation.Annotation."
|
||||
*
|
||||
* The methods in Object or Annotation meeting the other
|
||||
* criteria (no arguments, contrained return type, etc.)
|
||||
* above are:
|
||||
*
|
||||
* String toString()
|
||||
* int hashCode()
|
||||
* Class<? extends Annotation> annotationType()
|
||||
*/
|
||||
String methodName = method.getName();
|
||||
if ((methodName.equals("toString") && returnType == java.lang.String.class) ||
|
||||
(methodName.equals("hashCode") && returnType == int.class) ||
|
||||
(methodName.equals("annotationType") && returnType == java.lang.Class.class)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
return;
|
||||
else
|
||||
throw new AnnotationFormatError("Malformed method on an annotation type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of dynamicProxy.hashCode()
|
||||
*/
|
||||
private int hashCodeImpl() {
|
||||
int result = 0;
|
||||
for (Map.Entry<String, Object> e : memberValues.entrySet()) {
|
||||
result += (127 * e.getKey().hashCode()) ^
|
||||
memberValueHashCode(e.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes hashCode of a member value (in "dynamic proxy return form")
|
||||
*/
|
||||
private static int memberValueHashCode(Object value) {
|
||||
Class<?> type = value.getClass();
|
||||
if (!type.isArray()) // primitive, string, class, enum const,
|
||||
// or annotation
|
||||
return value.hashCode();
|
||||
|
||||
if (type == byte[].class)
|
||||
return Arrays.hashCode((byte[]) value);
|
||||
if (type == char[].class)
|
||||
return Arrays.hashCode((char[]) value);
|
||||
if (type == double[].class)
|
||||
return Arrays.hashCode((double[]) value);
|
||||
if (type == float[].class)
|
||||
return Arrays.hashCode((float[]) value);
|
||||
if (type == int[].class)
|
||||
return Arrays.hashCode((int[]) value);
|
||||
if (type == long[].class)
|
||||
return Arrays.hashCode((long[]) value);
|
||||
if (type == short[].class)
|
||||
return Arrays.hashCode((short[]) value);
|
||||
if (type == boolean[].class)
|
||||
return Arrays.hashCode((boolean[]) value);
|
||||
return Arrays.hashCode((Object[]) value);
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
ObjectInputStream.GetField fields = s.readFields();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null);
|
||||
|
||||
// Check to make sure that types have not evolved incompatibly
|
||||
|
||||
AnnotationType annotationType = null;
|
||||
try {
|
||||
annotationType = AnnotationType.getInstance(t);
|
||||
} catch(IllegalArgumentException e) {
|
||||
// Class is no longer an annotation type; time to punch out
|
||||
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
|
||||
}
|
||||
|
||||
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
|
||||
// consistent with runtime Map type
|
||||
Map<String, Object> mv = new LinkedHashMap<>();
|
||||
|
||||
// If there are annotation members without values, that
|
||||
// situation is handled by the invoke method.
|
||||
for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) {
|
||||
String name = memberValue.getKey();
|
||||
Object value = null;
|
||||
Class<?> memberType = memberTypes.get(name);
|
||||
if (memberType != null) { // i.e. member still exists
|
||||
value = memberValue.getValue();
|
||||
if (!(memberType.isInstance(value) ||
|
||||
value instanceof ExceptionProxy)) {
|
||||
value = new AnnotationTypeMismatchExceptionProxy(
|
||||
objectToString(value))
|
||||
.setMember(annotationType.members().get(name));
|
||||
}
|
||||
}
|
||||
mv.put(name, value);
|
||||
}
|
||||
|
||||
UnsafeAccessor.setType(this, t);
|
||||
UnsafeAccessor.setMemberValues(this, mv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a textual representation of the argument without calling
|
||||
* any overridable methods of the argument.
|
||||
*/
|
||||
private static String objectToString(Object value) {
|
||||
return value.getClass().getName() + "@" +
|
||||
Integer.toHexString(System.identityHashCode(value));
|
||||
}
|
||||
|
||||
private static class UnsafeAccessor {
|
||||
private static final sun.misc.Unsafe unsafe;
|
||||
private static final long typeOffset;
|
||||
private static final long memberValuesOffset;
|
||||
static {
|
||||
try {
|
||||
unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
typeOffset = unsafe.objectFieldOffset
|
||||
(AnnotationInvocationHandler.class.getDeclaredField("type"));
|
||||
memberValuesOffset = unsafe.objectFieldOffset
|
||||
(AnnotationInvocationHandler.class.getDeclaredField("memberValues"));
|
||||
} catch (Exception ex) {
|
||||
throw new ExceptionInInitializerError(ex);
|
||||
}
|
||||
}
|
||||
static void setType(AnnotationInvocationHandler o,
|
||||
Class<? extends Annotation> type) {
|
||||
unsafe.putObject(o, typeOffset, type);
|
||||
}
|
||||
|
||||
static void setMemberValues(AnnotationInvocationHandler o,
|
||||
Map<String, Object> memberValues) {
|
||||
unsafe.putObject(o, memberValuesOffset, memberValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
869
jdkSrc/jdk8/sun/reflect/annotation/AnnotationParser.java
Normal file
869
jdkSrc/jdk8/sun/reflect/annotation/AnnotationParser.java
Normal file
@@ -0,0 +1,869 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, 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.*;
|
||||
import java.util.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.lang.reflect.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.reflect.ConstantPool;
|
||||
|
||||
import sun.reflect.generics.parser.SignatureParser;
|
||||
import sun.reflect.generics.tree.TypeSignature;
|
||||
import sun.reflect.generics.factory.GenericsFactory;
|
||||
import sun.reflect.generics.factory.CoreReflectionFactory;
|
||||
import sun.reflect.generics.visitor.Reifier;
|
||||
import sun.reflect.generics.scope.ClassScope;
|
||||
|
||||
/**
|
||||
* Parser for Java programming language annotations. Translates
|
||||
* annotation byte streams emitted by compiler into annotation objects.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
public class AnnotationParser {
|
||||
/**
|
||||
* Parses the annotations described by the specified byte array.
|
||||
* resolving constant references in the specified constant pool.
|
||||
* The array must contain an array of annotations as described
|
||||
* in the RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* u2 num_annotations;
|
||||
* annotation annotations[num_annotations];
|
||||
*
|
||||
* @throws AnnotationFormatError if an annotation is found to be
|
||||
* malformed.
|
||||
*/
|
||||
public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
|
||||
byte[] rawAnnotations,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
if (rawAnnotations == null)
|
||||
return Collections.emptyMap();
|
||||
|
||||
try {
|
||||
return parseAnnotations2(rawAnnotations, constPool, container, null);
|
||||
} catch(BufferUnderflowException e) {
|
||||
throw new AnnotationFormatError("Unexpected end of annotations.");
|
||||
} catch(IllegalArgumentException e) {
|
||||
// Type mismatch in constant pool
|
||||
throw new AnnotationFormatError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
|
||||
* with an additional parameter {@code selectAnnotationClasses} which selects the
|
||||
* annotation types to parse (other than selected are quickly skipped).<p>
|
||||
* This method is only used to parse select meta annotations in the construction
|
||||
* phase of {@link AnnotationType} instances to prevent infinite recursion.
|
||||
*
|
||||
* @param selectAnnotationClasses an array of annotation types to select when parsing
|
||||
*/
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs") // selectAnnotationClasses is used safely
|
||||
static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
|
||||
byte[] rawAnnotations,
|
||||
ConstantPool constPool,
|
||||
Class<?> container,
|
||||
Class<? extends Annotation> ... selectAnnotationClasses) {
|
||||
if (rawAnnotations == null)
|
||||
return Collections.emptyMap();
|
||||
|
||||
try {
|
||||
return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
|
||||
} catch(BufferUnderflowException e) {
|
||||
throw new AnnotationFormatError("Unexpected end of annotations.");
|
||||
} catch(IllegalArgumentException e) {
|
||||
// Type mismatch in constant pool
|
||||
throw new AnnotationFormatError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
|
||||
byte[] rawAnnotations,
|
||||
ConstantPool constPool,
|
||||
Class<?> container,
|
||||
Class<? extends Annotation>[] selectAnnotationClasses) {
|
||||
Map<Class<? extends Annotation>, Annotation> result =
|
||||
new LinkedHashMap<Class<? extends Annotation>, Annotation>();
|
||||
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
|
||||
int numAnnotations = buf.getShort() & 0xFFFF;
|
||||
for (int i = 0; i < numAnnotations; i++) {
|
||||
Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
|
||||
if (a != null) {
|
||||
Class<? extends Annotation> klass = a.annotationType();
|
||||
if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
|
||||
result.put(klass, a) != null) {
|
||||
throw new AnnotationFormatError(
|
||||
"Duplicate annotation for class: "+klass+": " + a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the parameter annotations described by the specified byte array.
|
||||
* resolving constant references in the specified constant pool.
|
||||
* The array must contain an array of annotations as described
|
||||
* in the RuntimeVisibleParameterAnnotations_attribute:
|
||||
*
|
||||
* u1 num_parameters;
|
||||
* {
|
||||
* u2 num_annotations;
|
||||
* annotation annotations[num_annotations];
|
||||
* } parameter_annotations[num_parameters];
|
||||
*
|
||||
* Unlike parseAnnotations, rawAnnotations must not be null!
|
||||
* A null value must be handled by the caller. This is so because
|
||||
* we cannot determine the number of parameters if rawAnnotations
|
||||
* is null. Also, the caller should check that the number
|
||||
* of parameters indicated by the return value of this method
|
||||
* matches the actual number of method parameters. A mismatch
|
||||
* indicates that an AnnotationFormatError should be thrown.
|
||||
*
|
||||
* @throws AnnotationFormatError if an annotation is found to be
|
||||
* malformed.
|
||||
*/
|
||||
public static Annotation[][] parseParameterAnnotations(
|
||||
byte[] rawAnnotations,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
try {
|
||||
return parseParameterAnnotations2(rawAnnotations, constPool, container);
|
||||
} catch(BufferUnderflowException e) {
|
||||
throw new AnnotationFormatError(
|
||||
"Unexpected end of parameter annotations.");
|
||||
} catch(IllegalArgumentException e) {
|
||||
// Type mismatch in constant pool
|
||||
throw new AnnotationFormatError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Annotation[][] parseParameterAnnotations2(
|
||||
byte[] rawAnnotations,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
|
||||
int numParameters = buf.get() & 0xFF;
|
||||
Annotation[][] result = new Annotation[numParameters][];
|
||||
|
||||
for (int i = 0; i < numParameters; i++) {
|
||||
int numAnnotations = buf.getShort() & 0xFFFF;
|
||||
List<Annotation> annotations =
|
||||
new ArrayList<Annotation>(numAnnotations);
|
||||
for (int j = 0; j < numAnnotations; j++) {
|
||||
Annotation a = parseAnnotation(buf, constPool, container, false);
|
||||
if (a != null) {
|
||||
AnnotationType type = AnnotationType.getInstance(
|
||||
a.annotationType());
|
||||
if (type.retention() == RetentionPolicy.RUNTIME)
|
||||
annotations.add(a);
|
||||
}
|
||||
}
|
||||
result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
|
||||
new Annotation[0];
|
||||
|
||||
/**
|
||||
* Parses the annotation at the current position in the specified
|
||||
* byte buffer, resolving constant references in the specified constant
|
||||
* pool. The cursor of the byte buffer must point to an "annotation
|
||||
* structure" as described in the RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* annotation {
|
||||
* u2 type_index;
|
||||
* u2 num_member_value_pairs;
|
||||
* { u2 member_name_index;
|
||||
* member_value value;
|
||||
* } member_value_pairs[num_member_value_pairs];
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Returns the annotation, or null if the annotation's type cannot
|
||||
* be found by the VM, or is not a valid annotation type.
|
||||
*
|
||||
* @param exceptionOnMissingAnnotationClass if true, throw
|
||||
* TypeNotPresentException if a referenced annotation type is not
|
||||
* available at runtime
|
||||
*/
|
||||
static Annotation parseAnnotation(ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container,
|
||||
boolean exceptionOnMissingAnnotationClass) {
|
||||
return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Annotation parseAnnotation2(ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container,
|
||||
boolean exceptionOnMissingAnnotationClass,
|
||||
Class<? extends Annotation>[] selectAnnotationClasses) {
|
||||
int typeIndex = buf.getShort() & 0xFFFF;
|
||||
Class<? extends Annotation> annotationClass = null;
|
||||
String sig = "[unknown]";
|
||||
try {
|
||||
try {
|
||||
sig = constPool.getUTF8At(typeIndex);
|
||||
annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// support obsolete early jsr175 format class files
|
||||
annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
if (exceptionOnMissingAnnotationClass)
|
||||
// note: at this point sig is "[unknown]" or VM-style
|
||||
// name instead of a binary name
|
||||
throw new TypeNotPresentException(sig, e);
|
||||
skipAnnotation(buf, false);
|
||||
return null;
|
||||
}
|
||||
catch (TypeNotPresentException e) {
|
||||
if (exceptionOnMissingAnnotationClass)
|
||||
throw e;
|
||||
skipAnnotation(buf, false);
|
||||
return null;
|
||||
}
|
||||
if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
|
||||
skipAnnotation(buf, false);
|
||||
return null;
|
||||
}
|
||||
AnnotationType type = null;
|
||||
try {
|
||||
type = AnnotationType.getInstance(annotationClass);
|
||||
} catch (IllegalArgumentException e) {
|
||||
skipAnnotation(buf, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, Class<?>> memberTypes = type.memberTypes();
|
||||
Map<String, Object> memberValues =
|
||||
new LinkedHashMap<String, Object>(type.memberDefaults());
|
||||
|
||||
int numMembers = buf.getShort() & 0xFFFF;
|
||||
for (int i = 0; i < numMembers; i++) {
|
||||
int memberNameIndex = buf.getShort() & 0xFFFF;
|
||||
String memberName = constPool.getUTF8At(memberNameIndex);
|
||||
Class<?> memberType = memberTypes.get(memberName);
|
||||
|
||||
if (memberType == null) {
|
||||
// Member is no longer present in annotation type; ignore it
|
||||
skipMemberValue(buf);
|
||||
} else {
|
||||
Object value = parseMemberValue(memberType, buf, constPool, container);
|
||||
if (value instanceof AnnotationTypeMismatchExceptionProxy)
|
||||
((AnnotationTypeMismatchExceptionProxy) value).
|
||||
setMember(type.members().get(memberName));
|
||||
memberValues.put(memberName, value);
|
||||
}
|
||||
}
|
||||
return annotationForMap(annotationClass, memberValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an annotation of the given type backed by the given
|
||||
* member -> value map.
|
||||
*/
|
||||
public static Annotation annotationForMap(final Class<? extends Annotation> type,
|
||||
final Map<String, Object> memberValues)
|
||||
{
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
|
||||
public Annotation run() {
|
||||
return (Annotation) Proxy.newProxyInstance(
|
||||
type.getClassLoader(), new Class<?>[] { type },
|
||||
new AnnotationInvocationHandler(type, memberValues));
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the annotation member value at the current position in the
|
||||
* specified byte buffer, resolving constant references in the specified
|
||||
* constant pool. The cursor of the byte buffer must point to a
|
||||
* "member_value structure" as described in the
|
||||
* RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* member_value {
|
||||
* u1 tag;
|
||||
* union {
|
||||
* u2 const_value_index;
|
||||
* {
|
||||
* u2 type_name_index;
|
||||
* u2 const_name_index;
|
||||
* } enum_const_value;
|
||||
* u2 class_info_index;
|
||||
* annotation annotation_value;
|
||||
* {
|
||||
* u2 num_values;
|
||||
* member_value values[num_values];
|
||||
* } array_value;
|
||||
* } value;
|
||||
* }
|
||||
*
|
||||
* The member must be of the indicated type. If it is not, this
|
||||
* method returns an AnnotationTypeMismatchExceptionProxy.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Object parseMemberValue(Class<?> memberType,
|
||||
ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
Object result = null;
|
||||
int tag = buf.get();
|
||||
switch(tag) {
|
||||
case 'e':
|
||||
return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
|
||||
case 'c':
|
||||
result = parseClassValue(buf, constPool, container);
|
||||
break;
|
||||
case '@':
|
||||
result = parseAnnotation(buf, constPool, container, true);
|
||||
break;
|
||||
case '[':
|
||||
return parseArray(memberType, buf, constPool, container);
|
||||
default:
|
||||
result = parseConst(tag, buf, constPool);
|
||||
}
|
||||
|
||||
if (!(result instanceof ExceptionProxy) &&
|
||||
!memberType.isInstance(result))
|
||||
result = new AnnotationTypeMismatchExceptionProxy(
|
||||
result.getClass() + "[" + result + "]");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the primitive or String annotation member value indicated by
|
||||
* the specified tag byte at the current position in the specified byte
|
||||
* buffer, resolving constant reference in the specified constant pool.
|
||||
* The cursor of the byte buffer must point to an annotation member value
|
||||
* of the type indicated by the specified tag, as described in the
|
||||
* RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* u2 const_value_index;
|
||||
*/
|
||||
private static Object parseConst(int tag,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
int constIndex = buf.getShort() & 0xFFFF;
|
||||
switch(tag) {
|
||||
case 'B':
|
||||
return Byte.valueOf((byte) constPool.getIntAt(constIndex));
|
||||
case 'C':
|
||||
return Character.valueOf((char) constPool.getIntAt(constIndex));
|
||||
case 'D':
|
||||
return Double.valueOf(constPool.getDoubleAt(constIndex));
|
||||
case 'F':
|
||||
return Float.valueOf(constPool.getFloatAt(constIndex));
|
||||
case 'I':
|
||||
return Integer.valueOf(constPool.getIntAt(constIndex));
|
||||
case 'J':
|
||||
return Long.valueOf(constPool.getLongAt(constIndex));
|
||||
case 'S':
|
||||
return Short.valueOf((short) constPool.getIntAt(constIndex));
|
||||
case 'Z':
|
||||
return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
|
||||
case 's':
|
||||
return constPool.getUTF8At(constIndex);
|
||||
default:
|
||||
throw new AnnotationFormatError(
|
||||
"Invalid member-value tag in annotation: " + tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the Class member value at the current position in the
|
||||
* specified byte buffer, resolving constant references in the specified
|
||||
* constant pool. The cursor of the byte buffer must point to a "class
|
||||
* info index" as described in the RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* u2 class_info_index;
|
||||
*/
|
||||
private static Object parseClassValue(ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
int classIndex = buf.getShort() & 0xFFFF;
|
||||
try {
|
||||
try {
|
||||
String sig = constPool.getUTF8At(classIndex);
|
||||
return parseSig(sig, container);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// support obsolete early jsr175 format class files
|
||||
return constPool.getClassAt(classIndex);
|
||||
}
|
||||
} catch (NoClassDefFoundError e) {
|
||||
return new TypeNotPresentExceptionProxy("[unknown]", e);
|
||||
}
|
||||
catch (TypeNotPresentException e) {
|
||||
return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> parseSig(String sig, Class<?> container) {
|
||||
if (sig.equals("V")) return void.class;
|
||||
SignatureParser parser = SignatureParser.make();
|
||||
TypeSignature typeSig = parser.parseTypeSig(sig);
|
||||
GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
|
||||
Reifier reify = Reifier.make(factory);
|
||||
typeSig.accept(reify);
|
||||
Type result = reify.getResult();
|
||||
return toClass(result);
|
||||
}
|
||||
static Class<?> toClass(Type o) {
|
||||
if (o instanceof GenericArrayType)
|
||||
return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
|
||||
0)
|
||||
.getClass();
|
||||
return (Class)o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the enum constant member value at the current position in the
|
||||
* specified byte buffer, resolving constant references in the specified
|
||||
* constant pool. The cursor of the byte buffer must point to a
|
||||
* "enum_const_value structure" as described in the
|
||||
* RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* {
|
||||
* u2 type_name_index;
|
||||
* u2 const_name_index;
|
||||
* } enum_const_value;
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
int typeNameIndex = buf.getShort() & 0xFFFF;
|
||||
String typeName = constPool.getUTF8At(typeNameIndex);
|
||||
int constNameIndex = buf.getShort() & 0xFFFF;
|
||||
String constName = constPool.getUTF8At(constNameIndex);
|
||||
|
||||
if (!typeName.endsWith(";")) {
|
||||
// support now-obsolete early jsr175-format class files.
|
||||
if (!enumType.getName().equals(typeName))
|
||||
return new AnnotationTypeMismatchExceptionProxy(
|
||||
typeName + "." + constName);
|
||||
} else if (enumType != parseSig(typeName, container)) {
|
||||
return new AnnotationTypeMismatchExceptionProxy(
|
||||
typeName + "." + constName);
|
||||
}
|
||||
|
||||
try {
|
||||
return Enum.valueOf(enumType, constName);
|
||||
} catch(IllegalArgumentException e) {
|
||||
return new EnumConstantNotPresentExceptionProxy(
|
||||
(Class<? extends Enum<?>>)enumType, constName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the array value at the current position in the specified byte
|
||||
* buffer, resolving constant references in the specified constant pool.
|
||||
* The cursor of the byte buffer must point to an array value struct
|
||||
* as specified in the RuntimeVisibleAnnotations_attribute:
|
||||
*
|
||||
* {
|
||||
* u2 num_values;
|
||||
* member_value values[num_values];
|
||||
* } array_value;
|
||||
*
|
||||
* If the array values do not match arrayType, an
|
||||
* AnnotationTypeMismatchExceptionProxy will be returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Object parseArray(Class<?> arrayType,
|
||||
ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
int length = buf.getShort() & 0xFFFF; // Number of array components
|
||||
Class<?> componentType = arrayType.getComponentType();
|
||||
|
||||
if (componentType == byte.class) {
|
||||
return parseByteArray(length, buf, constPool);
|
||||
} else if (componentType == char.class) {
|
||||
return parseCharArray(length, buf, constPool);
|
||||
} else if (componentType == double.class) {
|
||||
return parseDoubleArray(length, buf, constPool);
|
||||
} else if (componentType == float.class) {
|
||||
return parseFloatArray(length, buf, constPool);
|
||||
} else if (componentType == int.class) {
|
||||
return parseIntArray(length, buf, constPool);
|
||||
} else if (componentType == long.class) {
|
||||
return parseLongArray(length, buf, constPool);
|
||||
} else if (componentType == short.class) {
|
||||
return parseShortArray(length, buf, constPool);
|
||||
} else if (componentType == boolean.class) {
|
||||
return parseBooleanArray(length, buf, constPool);
|
||||
} else if (componentType == String.class) {
|
||||
return parseStringArray(length, buf, constPool);
|
||||
} else if (componentType == Class.class) {
|
||||
return parseClassArray(length, buf, constPool, container);
|
||||
} else if (componentType.isEnum()) {
|
||||
return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf,
|
||||
constPool, container);
|
||||
} else {
|
||||
assert componentType.isAnnotation();
|
||||
return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,
|
||||
constPool, container);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object parseByteArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
byte[] result = new byte[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'B') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = (byte) constPool.getIntAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseCharArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
char[] result = new char[length];
|
||||
boolean typeMismatch = false;
|
||||
byte tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'C') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = (char) constPool.getIntAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseDoubleArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
double[] result = new double[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'D') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = constPool.getDoubleAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseFloatArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
float[] result = new float[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'F') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = constPool.getFloatAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseIntArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
int[] result = new int[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'I') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = constPool.getIntAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseLongArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
long[] result = new long[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'J') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = constPool.getLongAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseShortArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
short[] result = new short[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'S') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = (short) constPool.getIntAt(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseBooleanArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
boolean[] result = new boolean[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'Z') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = (constPool.getIntAt(index) != 0);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseStringArray(int length,
|
||||
ByteBuffer buf, ConstantPool constPool) {
|
||||
String[] result = new String[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 's') {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
result[i] = constPool.getUTF8At(index);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseClassArray(int length,
|
||||
ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
Object[] result = new Class<?>[length];
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'c') {
|
||||
result[i] = parseClassValue(buf, constPool, container);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType,
|
||||
ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
Object[] result = (Object[]) Array.newInstance(enumType, length);
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == 'e') {
|
||||
result[i] = parseEnumValue(enumType, buf, constPool, container);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
private static Object parseAnnotationArray(int length,
|
||||
Class<? extends Annotation> annotationType,
|
||||
ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container) {
|
||||
Object[] result = (Object[]) Array.newInstance(annotationType, length);
|
||||
boolean typeMismatch = false;
|
||||
int tag = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tag = buf.get();
|
||||
if (tag == '@') {
|
||||
result[i] = parseAnnotation(buf, constPool, container, true);
|
||||
} else {
|
||||
skipMemberValue(tag, buf);
|
||||
typeMismatch = true;
|
||||
}
|
||||
}
|
||||
return typeMismatch ? exceptionProxy(tag) : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an appropriate exception proxy for a mismatching array
|
||||
* annotation where the erroneous array has the specified tag.
|
||||
*/
|
||||
private static ExceptionProxy exceptionProxy(int tag) {
|
||||
return new AnnotationTypeMismatchExceptionProxy(
|
||||
"Array with component tag: " + tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the annotation at the current position in the specified
|
||||
* byte buffer. The cursor of the byte buffer must point to
|
||||
* an "annotation structure" OR two bytes into an annotation
|
||||
* structure (i.e., after the type index).
|
||||
*
|
||||
* @parameter complete true if the byte buffer points to the beginning
|
||||
* of an annotation structure (rather than two bytes in).
|
||||
*/
|
||||
private static void skipAnnotation(ByteBuffer buf, boolean complete) {
|
||||
if (complete)
|
||||
buf.getShort(); // Skip type index
|
||||
int numMembers = buf.getShort() & 0xFFFF;
|
||||
for (int i = 0; i < numMembers; i++) {
|
||||
buf.getShort(); // Skip memberNameIndex
|
||||
skipMemberValue(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the annotation member value at the current position in the
|
||||
* specified byte buffer. The cursor of the byte buffer must point to a
|
||||
* "member_value structure."
|
||||
*/
|
||||
private static void skipMemberValue(ByteBuffer buf) {
|
||||
int tag = buf.get();
|
||||
skipMemberValue(tag, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the annotation member value at the current position in the
|
||||
* specified byte buffer. The cursor of the byte buffer must point
|
||||
* immediately after the tag in a "member_value structure."
|
||||
*/
|
||||
private static void skipMemberValue(int tag, ByteBuffer buf) {
|
||||
switch(tag) {
|
||||
case 'e': // Enum value
|
||||
buf.getInt(); // (Two shorts, actually.)
|
||||
break;
|
||||
case '@':
|
||||
skipAnnotation(buf, true);
|
||||
break;
|
||||
case '[':
|
||||
skipArray(buf);
|
||||
break;
|
||||
default:
|
||||
// Class, primitive, or String
|
||||
buf.getShort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips the array value at the current position in the specified byte
|
||||
* buffer. The cursor of the byte buffer must point to an array value
|
||||
* struct.
|
||||
*/
|
||||
private static void skipArray(ByteBuffer buf) {
|
||||
int length = buf.getShort() & 0xFFFF;
|
||||
for (int i = 0; i < length; i++)
|
||||
skipMemberValue(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for given {@code element} in given {@code array} by identity.
|
||||
* Returns {@code true} if found {@code false} if not.
|
||||
*/
|
||||
private static boolean contains(Object[] array, Object element) {
|
||||
for (Object e : array)
|
||||
if (e == element)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method converts the annotation map returned by the parseAnnotations()
|
||||
* method to an array. It is called by Field.getDeclaredAnnotations(),
|
||||
* Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
|
||||
* This avoids the reflection classes to load the Annotation class until
|
||||
* it is needed.
|
||||
*/
|
||||
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
||||
public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
|
||||
return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
|
||||
}
|
||||
239
jdkSrc/jdk8/sun/reflect/annotation/AnnotationSupport.java
Normal file
239
jdkSrc/jdk8/sun/reflect/annotation/AnnotationSupport.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, 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.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.misc.JavaLangAccess;
|
||||
|
||||
public final class AnnotationSupport {
|
||||
private static final JavaLangAccess LANG_ACCESS = sun.misc.SharedSecrets.getJavaLangAccess();
|
||||
|
||||
/**
|
||||
* Finds and returns all annotations in {@code annotations} matching
|
||||
* the given {@code annoClass}.
|
||||
*
|
||||
* Apart from annotations directly present in {@code annotations} this
|
||||
* method searches for annotations inside containers i.e. indirectly
|
||||
* present annotations.
|
||||
*
|
||||
* The order of the elements in the array returned depends on the iteration
|
||||
* order of the provided map. Specifically, the directly present annotations
|
||||
* come before the indirectly present annotations if and only if the
|
||||
* directly present annotations come before the indirectly present
|
||||
* annotations in the map.
|
||||
*
|
||||
* @param annotations the {@code Map} in which to search for annotations
|
||||
* @param annoClass the type of annotation to search for
|
||||
*
|
||||
* @return an array of instances of {@code annoClass} or an empty
|
||||
* array if none were found
|
||||
*/
|
||||
public static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent(
|
||||
Map<Class<? extends Annotation>, Annotation> annotations,
|
||||
Class<A> annoClass) {
|
||||
List<A> result = new ArrayList<A>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
A direct = (A) annotations.get(annoClass);
|
||||
if (direct != null)
|
||||
result.add(direct);
|
||||
|
||||
A[] indirect = getIndirectlyPresent(annotations, annoClass);
|
||||
if (indirect != null && indirect.length != 0) {
|
||||
boolean indirectFirst = direct == null ||
|
||||
containerBeforeContainee(annotations, annoClass);
|
||||
|
||||
result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
A[] arr = (A[]) Array.newInstance(annoClass, result.size());
|
||||
return result.toArray(arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns all annotations matching the given {@code annoClass}
|
||||
* indirectly present in {@code annotations}.
|
||||
*
|
||||
* @param annotations annotations to search indexed by their types
|
||||
* @param annoClass the type of annotation to search for
|
||||
*
|
||||
* @return an array of instances of {@code annoClass} or an empty array if no
|
||||
* indirectly present annotations were found
|
||||
*/
|
||||
private static <A extends Annotation> A[] getIndirectlyPresent(
|
||||
Map<Class<? extends Annotation>, Annotation> annotations,
|
||||
Class<A> annoClass) {
|
||||
|
||||
Repeatable repeatable = annoClass.getDeclaredAnnotation(Repeatable.class);
|
||||
if (repeatable == null)
|
||||
return null; // Not repeatable -> no indirectly present annotations
|
||||
|
||||
Class<? extends Annotation> containerClass = repeatable.value();
|
||||
|
||||
Annotation container = annotations.get(containerClass);
|
||||
if (container == null)
|
||||
return null;
|
||||
|
||||
// Unpack container
|
||||
A[] valueArray = getValueArray(container);
|
||||
checkTypes(valueArray, container, annoClass);
|
||||
|
||||
return valueArray;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Figures out if conatiner class comes before containee class among the
|
||||
* keys of the given map.
|
||||
*
|
||||
* @return true if container class is found before containee class when
|
||||
* iterating over annotations.keySet().
|
||||
*/
|
||||
private static <A extends Annotation> boolean containerBeforeContainee(
|
||||
Map<Class<? extends Annotation>, Annotation> annotations,
|
||||
Class<A> annoClass) {
|
||||
|
||||
Class<? extends Annotation> containerClass =
|
||||
annoClass.getDeclaredAnnotation(Repeatable.class).value();
|
||||
|
||||
for (Class<? extends Annotation> c : annotations.keySet()) {
|
||||
if (c == containerClass) return true;
|
||||
if (c == annoClass) return false;
|
||||
}
|
||||
|
||||
// Neither containee nor container present
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds and returns all associated annotations matching the given class.
|
||||
*
|
||||
* The order of the elements in the array returned depends on the iteration
|
||||
* order of the provided maps. Specifically, the directly present annotations
|
||||
* come before the indirectly present annotations if and only if the
|
||||
* directly present annotations come before the indirectly present
|
||||
* annotations in the relevant map.
|
||||
*
|
||||
* @param declaredAnnotations the declared annotations indexed by their types
|
||||
* @param decl the class declaration on which to search for annotations
|
||||
* @param annoClass the type of annotation to search for
|
||||
*
|
||||
* @return an array of instances of {@code annoClass} or an empty array if none were found.
|
||||
*/
|
||||
public static <A extends Annotation> A[] getAssociatedAnnotations(
|
||||
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
|
||||
Class<?> decl,
|
||||
Class<A> annoClass) {
|
||||
Objects.requireNonNull(decl);
|
||||
|
||||
// Search declared
|
||||
A[] result = getDirectlyAndIndirectlyPresent(declaredAnnotations, annoClass);
|
||||
|
||||
// Search inherited
|
||||
if(AnnotationType.getInstance(annoClass).isInherited()) {
|
||||
Class<?> superDecl = decl.getSuperclass();
|
||||
while (result.length == 0 && superDecl != null) {
|
||||
result = getDirectlyAndIndirectlyPresent(LANG_ACCESS.getDeclaredAnnotationMap(superDecl), annoClass);
|
||||
superDecl = superDecl.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Reflectively invoke the values-method of the given annotation
|
||||
* (container), cast it to an array of annotations and return the result.
|
||||
*/
|
||||
private static <A extends Annotation> A[] getValueArray(Annotation container) {
|
||||
try {
|
||||
// According to JLS the container must have an array-valued value
|
||||
// method. Get the AnnotationType, get the "value" method and invoke
|
||||
// it to get the content.
|
||||
|
||||
Class<? extends Annotation> containerClass = container.annotationType();
|
||||
AnnotationType annoType = AnnotationType.getInstance(containerClass);
|
||||
if (annoType == null)
|
||||
throw invalidContainerException(container, null);
|
||||
|
||||
Method m = annoType.members().get("value");
|
||||
if (m == null)
|
||||
throw invalidContainerException(container, null);
|
||||
|
||||
m.setAccessible(true);
|
||||
|
||||
// This will erase to (Annotation[]) but we do a runtime cast on the
|
||||
// return-value in the method that call this method.
|
||||
@SuppressWarnings("unchecked")
|
||||
A[] values = (A[]) m.invoke(container);
|
||||
|
||||
return values;
|
||||
|
||||
} catch (IllegalAccessException | // couldn't loosen security
|
||||
IllegalArgumentException | // parameters doesn't match
|
||||
InvocationTargetException | // the value method threw an exception
|
||||
ClassCastException e) {
|
||||
|
||||
throw invalidContainerException(container, e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static AnnotationFormatError invalidContainerException(Annotation anno,
|
||||
Throwable cause) {
|
||||
return new AnnotationFormatError(
|
||||
anno + " is an invalid container for repeating annotations",
|
||||
cause);
|
||||
}
|
||||
|
||||
|
||||
/* Sanity check type of all the annotation instances of type {@code annoClass}
|
||||
* from {@code container}.
|
||||
*/
|
||||
private static <A extends Annotation> void checkTypes(A[] annotations,
|
||||
Annotation container,
|
||||
Class<A> annoClass) {
|
||||
for (A a : annotations) {
|
||||
if (!annoClass.isInstance(a)) {
|
||||
throw new AnnotationFormatError(
|
||||
String.format("%s is an invalid container for " +
|
||||
"repeating annotations of type: %s",
|
||||
container, annoClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
238
jdkSrc/jdk8/sun/reflect/annotation/AnnotationType.java
Normal file
238
jdkSrc/jdk8/sun/reflect/annotation/AnnotationType.java
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, 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 sun.misc.JavaLangAccess;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Represents an annotation type at run time. Used to type-check annotations
|
||||
* and apply member defaults.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
public class AnnotationType {
|
||||
/**
|
||||
* Member name -> type mapping. Note that primitive types
|
||||
* are represented by the class objects for the corresponding wrapper
|
||||
* types. This matches the return value that must be used for a
|
||||
* dynamic proxy, allowing for a simple isInstance test.
|
||||
*/
|
||||
private final Map<String, Class<?>> memberTypes;
|
||||
|
||||
/**
|
||||
* Member name -> default value mapping.
|
||||
*/
|
||||
private final Map<String, Object> memberDefaults;
|
||||
|
||||
/**
|
||||
* Member name -> Method object mapping. This (and its assoicated
|
||||
* accessor) are used only to generate AnnotationTypeMismatchExceptions.
|
||||
*/
|
||||
private final Map<String, Method> members;
|
||||
|
||||
/**
|
||||
* The retention policy for this annotation type.
|
||||
*/
|
||||
private final RetentionPolicy retention;
|
||||
|
||||
/**
|
||||
* Whether this annotation type is inherited.
|
||||
*/
|
||||
private final boolean inherited;
|
||||
|
||||
/**
|
||||
* Returns an AnnotationType instance for the specified annotation type.
|
||||
*
|
||||
* @throw IllegalArgumentException if the specified class object for
|
||||
* does not represent a valid annotation type
|
||||
*/
|
||||
public static AnnotationType getInstance(
|
||||
Class<? extends Annotation> annotationClass)
|
||||
{
|
||||
JavaLangAccess jla = sun.misc.SharedSecrets.getJavaLangAccess();
|
||||
AnnotationType result = jla.getAnnotationType(annotationClass); // volatile read
|
||||
if (result == null) {
|
||||
result = new AnnotationType(annotationClass);
|
||||
// try to CAS the AnnotationType: null -> result
|
||||
if (!jla.casAnnotationType(annotationClass, null, result)) {
|
||||
// somebody was quicker -> read it's result
|
||||
result = jla.getAnnotationType(annotationClass);
|
||||
assert result != null;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sole constructor.
|
||||
*
|
||||
* @param annotationClass the class object for the annotation type
|
||||
* @throw IllegalArgumentException if the specified class object for
|
||||
* does not represent a valid annotation type
|
||||
*/
|
||||
private AnnotationType(final Class<? extends Annotation> annotationClass) {
|
||||
if (!annotationClass.isAnnotation())
|
||||
throw new IllegalArgumentException("Not an annotation type");
|
||||
|
||||
Method[] methods =
|
||||
AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
public Method[] run() {
|
||||
// Initialize memberTypes and defaultValues
|
||||
return annotationClass.getDeclaredMethods();
|
||||
}
|
||||
});
|
||||
|
||||
memberTypes = new HashMap<String,Class<?>>(methods.length+1, 1.0f);
|
||||
memberDefaults = new HashMap<String, Object>(0);
|
||||
members = new HashMap<String, Method>(methods.length+1, 1.0f);
|
||||
|
||||
for (Method method : methods) {
|
||||
if (Modifier.isPublic(method.getModifiers()) &&
|
||||
Modifier.isAbstract(method.getModifiers()) &&
|
||||
!method.isSynthetic()) {
|
||||
if (method.getParameterTypes().length != 0) {
|
||||
throw new IllegalArgumentException(method + " has params");
|
||||
}
|
||||
String name = method.getName();
|
||||
Class<?> type = method.getReturnType();
|
||||
memberTypes.put(name, invocationHandlerReturnType(type));
|
||||
members.put(name, method);
|
||||
|
||||
Object defaultValue = method.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
memberDefaults.put(name, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize retention, & inherited fields. Special treatment
|
||||
// of the corresponding annotation types breaks infinite recursion.
|
||||
if (annotationClass != Retention.class &&
|
||||
annotationClass != Inherited.class) {
|
||||
JavaLangAccess jla = sun.misc.SharedSecrets.getJavaLangAccess();
|
||||
Map<Class<? extends Annotation>, Annotation> metaAnnotations =
|
||||
AnnotationParser.parseSelectAnnotations(
|
||||
jla.getRawClassAnnotations(annotationClass),
|
||||
jla.getConstantPool(annotationClass),
|
||||
annotationClass,
|
||||
Retention.class, Inherited.class
|
||||
);
|
||||
Retention ret = (Retention) metaAnnotations.get(Retention.class);
|
||||
retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
|
||||
inherited = metaAnnotations.containsKey(Inherited.class);
|
||||
}
|
||||
else {
|
||||
retention = RetentionPolicy.RUNTIME;
|
||||
inherited = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type that must be returned by the invocation handler
|
||||
* of a dynamic proxy in order to have the dynamic proxy return
|
||||
* the specified type (which is assumed to be a legal member type
|
||||
* for an annotation).
|
||||
*/
|
||||
public static Class<?> invocationHandlerReturnType(Class<?> type) {
|
||||
// Translate primitives to wrappers
|
||||
if (type == byte.class)
|
||||
return Byte.class;
|
||||
if (type == char.class)
|
||||
return Character.class;
|
||||
if (type == double.class)
|
||||
return Double.class;
|
||||
if (type == float.class)
|
||||
return Float.class;
|
||||
if (type == int.class)
|
||||
return Integer.class;
|
||||
if (type == long.class)
|
||||
return Long.class;
|
||||
if (type == short.class)
|
||||
return Short.class;
|
||||
if (type == boolean.class)
|
||||
return Boolean.class;
|
||||
|
||||
// Otherwise, just return declared type
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns member types for this annotation type
|
||||
* (member name -> type mapping).
|
||||
*/
|
||||
public Map<String, Class<?>> memberTypes() {
|
||||
return memberTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns members of this annotation type
|
||||
* (member name -> associated Method object mapping).
|
||||
*/
|
||||
public Map<String, Method> members() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default values for this annotation type
|
||||
* (Member name -> default value mapping).
|
||||
*/
|
||||
public Map<String, Object> memberDefaults() {
|
||||
return memberDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the retention policy for this annotation type.
|
||||
*/
|
||||
public RetentionPolicy retention() {
|
||||
return retention;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this this annotation type is inherited.
|
||||
*/
|
||||
public boolean isInherited() {
|
||||
return inherited;
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging.
|
||||
*/
|
||||
public String toString() {
|
||||
return "Annotation Type:\n" +
|
||||
" Member types: " + memberTypes + "\n" +
|
||||
" Member defaults: " + memberDefaults + "\n" +
|
||||
" Retention policy: " + retention + "\n" +
|
||||
" Inherited: " + inherited;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, 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.*;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* ExceptionProxy for AnnotationTypeMismatchException.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
class AnnotationTypeMismatchExceptionProxy extends ExceptionProxy {
|
||||
private static final long serialVersionUID = 7844069490309503934L;
|
||||
private Method member;
|
||||
private String foundType;
|
||||
|
||||
/**
|
||||
* It turns out to be convenient to construct these proxies in
|
||||
* two stages. Since this is a private implementation class, we
|
||||
* permit ourselves this liberty even though it's normally a very
|
||||
* bad idea.
|
||||
*/
|
||||
AnnotationTypeMismatchExceptionProxy(String foundType) {
|
||||
this.foundType = foundType;
|
||||
}
|
||||
|
||||
AnnotationTypeMismatchExceptionProxy setMember(Method member) {
|
||||
this.member = member;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected RuntimeException generateException() {
|
||||
return new AnnotationTypeMismatchException(member, foundType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, 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;
|
||||
|
||||
/**
|
||||
* ExceptionProxy for EnumConstantNotPresentException.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
public class EnumConstantNotPresentExceptionProxy extends ExceptionProxy {
|
||||
private static final long serialVersionUID = -604662101303187330L;
|
||||
Class<? extends Enum<?>> enumType;
|
||||
String constName;
|
||||
|
||||
public EnumConstantNotPresentExceptionProxy(Class<? extends Enum<?>> enumType,
|
||||
String constName) {
|
||||
this.enumType = enumType;
|
||||
this.constName = constName;
|
||||
}
|
||||
|
||||
protected RuntimeException generateException() {
|
||||
return new EnumConstantNotPresentException(enumType, constName);
|
||||
}
|
||||
}
|
||||
41
jdkSrc/jdk8/sun/reflect/annotation/ExceptionProxy.java
Normal file
41
jdkSrc/jdk8/sun/reflect/annotation/ExceptionProxy.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 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;
|
||||
|
||||
/**
|
||||
* An instance of this class is stored in an AnnotationInvocationHandler's
|
||||
* "memberValues" map in lieu of a value for an annotation member that
|
||||
* cannot be returned due to some exceptional condition (typically some
|
||||
* form of illegal evolution of the annotation class). The ExceptionProxy
|
||||
* instance describes the exception that the dynamic proxy should throw if
|
||||
* it is queried for this member.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
public abstract class ExceptionProxy implements java.io.Serializable {
|
||||
protected abstract RuntimeException generateException();
|
||||
}
|
||||
229
jdkSrc/jdk8/sun/reflect/annotation/TypeAnnotation.java
Normal file
229
jdkSrc/jdk8/sun/reflect/annotation/TypeAnnotation.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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);
|
||||
}
|
||||
|
||||
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(new TypeAnnotation[0]);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
503
jdkSrc/jdk8/sun/reflect/annotation/TypeAnnotationParser.java
Normal file
503
jdkSrc/jdk8/sun/reflect/annotation/TypeAnnotationParser.java
Normal file
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import sun.misc.JavaLangAccess;
|
||||
import sun.reflect.ConstantPool;
|
||||
import static sun.reflect.annotation.TypeAnnotation.*;
|
||||
|
||||
/**
|
||||
* TypeAnnotationParser implements the logic needed to parse
|
||||
* TypeAnnotations from an array of bytes.
|
||||
*/
|
||||
public final class TypeAnnotationParser {
|
||||
private static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0];
|
||||
|
||||
/**
|
||||
* Build an AnnotatedType from the parameters supplied.
|
||||
*
|
||||
* This method and {@code buildAnnotatedTypes} are probably
|
||||
* the entry points you are looking for.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the declaration this type annotation is on
|
||||
* @param container the Class this type annotation is on (may be the same as decl)
|
||||
* @param type the type the AnnotatedType corresponds to
|
||||
* @param filter the type annotation targets included in this AnnotatedType
|
||||
*/
|
||||
public static AnnotatedType buildAnnotatedType(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement decl,
|
||||
Class<?> container,
|
||||
Type type,
|
||||
TypeAnnotationTarget filter) {
|
||||
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
container);
|
||||
List<TypeAnnotation> l = new ArrayList<>(tas.length);
|
||||
for (TypeAnnotation t : tas) {
|
||||
TypeAnnotationTargetInfo ti = t.getTargetInfo();
|
||||
if (ti.getTarget() == filter)
|
||||
l.add(t);
|
||||
}
|
||||
TypeAnnotation[] typeAnnotations = l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY);
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(type,
|
||||
LocationInfo.BASE_LOCATION,
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an array of AnnotatedTypes from the parameters supplied.
|
||||
*
|
||||
* This method and {@code buildAnnotatedType} are probably
|
||||
* the entry points you are looking for.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the declaration this type annotation is on
|
||||
* @param container the Class this type annotation is on (may be the same as decl)
|
||||
* @param types the Types the AnnotatedTypes corresponds to
|
||||
* @param filter the type annotation targets that included in this AnnotatedType
|
||||
*/
|
||||
public static AnnotatedType[] buildAnnotatedTypes(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement decl,
|
||||
Class<?> container,
|
||||
Type[] types,
|
||||
TypeAnnotationTarget filter) {
|
||||
int size = types.length;
|
||||
AnnotatedType[] result = new AnnotatedType[size];
|
||||
Arrays.fill(result, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE);
|
||||
@SuppressWarnings("rawtypes")
|
||||
ArrayList[] l = new ArrayList[size]; // array of ArrayList<TypeAnnotation>
|
||||
|
||||
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
container);
|
||||
for (TypeAnnotation t : tas) {
|
||||
TypeAnnotationTargetInfo ti = t.getTargetInfo();
|
||||
if (ti.getTarget() == filter) {
|
||||
int pos = ti.getCount();
|
||||
if (l[pos] == null) {
|
||||
ArrayList<TypeAnnotation> tmp = new ArrayList<>(tas.length);
|
||||
l[pos] = tmp;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<TypeAnnotation> tmp = l[pos];
|
||||
tmp.add(t);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<TypeAnnotation> list = l[i];
|
||||
TypeAnnotation[] typeAnnotations;
|
||||
if (list != null) {
|
||||
typeAnnotations = list.toArray(new TypeAnnotation[list.size()]);
|
||||
} else {
|
||||
typeAnnotations = EMPTY_TYPE_ANNOTATION_ARRAY;
|
||||
}
|
||||
result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i],
|
||||
LocationInfo.BASE_LOCATION,
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Class helpers
|
||||
|
||||
/**
|
||||
* Build an AnnotatedType for the class decl's supertype.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the Class which annotated supertype is being built
|
||||
*/
|
||||
public static AnnotatedType buildAnnotatedSuperclass(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
Class<?> decl) {
|
||||
Type supertype = decl.getGenericSuperclass();
|
||||
if (supertype == null)
|
||||
return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE;
|
||||
return buildAnnotatedType(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
decl,
|
||||
supertype,
|
||||
TypeAnnotationTarget.CLASS_EXTENDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an array of AnnotatedTypes for the class decl's implemented
|
||||
* interfaces.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the Class whose annotated implemented interfaces is being built
|
||||
*/
|
||||
public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
Class<?> decl) {
|
||||
if (decl == Object.class ||
|
||||
decl.isArray() ||
|
||||
decl.isPrimitive() ||
|
||||
decl == Void.TYPE)
|
||||
return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE_ARRAY;
|
||||
return buildAnnotatedTypes(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
decl,
|
||||
decl.getGenericInterfaces(),
|
||||
TypeAnnotationTarget.CLASS_IMPLEMENTS);
|
||||
}
|
||||
|
||||
// TypeVariable helpers
|
||||
|
||||
/**
|
||||
* Parse regular annotations on a TypeVariable declared on genericDecl.
|
||||
*
|
||||
* Regular Annotations on TypeVariables are stored in the type
|
||||
* annotation byte[] in the class file.
|
||||
*
|
||||
* @param genericsDecl the declaration declaring the type variable
|
||||
* @param typeVarIndex the 0-based index of this type variable in the declaration
|
||||
*/
|
||||
public static <D extends GenericDeclaration> Annotation[] parseTypeVariableAnnotations(D genericDecl,
|
||||
int typeVarIndex) {
|
||||
AnnotatedElement decl;
|
||||
TypeAnnotationTarget predicate;
|
||||
if (genericDecl instanceof Class) {
|
||||
decl = (Class<?>)genericDecl;
|
||||
predicate = TypeAnnotationTarget.CLASS_TYPE_PARAMETER;
|
||||
} else if (genericDecl instanceof Executable) {
|
||||
decl = (Executable)genericDecl;
|
||||
predicate = TypeAnnotationTarget.METHOD_TYPE_PARAMETER;
|
||||
} else {
|
||||
throw new AssertionError("Unknown GenericDeclaration " + genericDecl + "\nthis should not happen.");
|
||||
}
|
||||
List<TypeAnnotation> typeVarAnnos = TypeAnnotation.filter(parseAllTypeAnnotations(decl),
|
||||
predicate);
|
||||
List<Annotation> res = new ArrayList<>(typeVarAnnos.size());
|
||||
for (TypeAnnotation t : typeVarAnnos)
|
||||
if (t.getTargetInfo().getCount() == typeVarIndex)
|
||||
res.add(t.getAnnotation());
|
||||
return res.toArray(new Annotation[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an array of AnnotatedTypes for the declaration decl's bounds.
|
||||
*
|
||||
* @param bounds the bounds corresponding to the annotated bounds
|
||||
* @param decl the declaration whose annotated bounds is being built
|
||||
* @param typeVarIndex the index of this type variable on the decl
|
||||
*/
|
||||
public static <D extends GenericDeclaration> AnnotatedType[] parseAnnotatedBounds(Type[] bounds,
|
||||
D decl,
|
||||
int typeVarIndex) {
|
||||
return parseAnnotatedBounds(bounds, decl, typeVarIndex, LocationInfo.BASE_LOCATION);
|
||||
}
|
||||
//helper for above
|
||||
private static <D extends GenericDeclaration> AnnotatedType[] parseAnnotatedBounds(Type[] bounds,
|
||||
D decl,
|
||||
int typeVarIndex,
|
||||
LocationInfo loc) {
|
||||
List<TypeAnnotation> candidates = fetchBounds(decl);
|
||||
if (bounds != null) {
|
||||
int startIndex = 0;
|
||||
AnnotatedType[] res = new AnnotatedType[bounds.length];
|
||||
|
||||
// Adjust bounds index
|
||||
//
|
||||
// Figure out if the type annotations for this bound starts with 0
|
||||
// or 1. The spec says within a bound the 0:th type annotation will
|
||||
// always be on an bound of a Class type (not Interface type). So
|
||||
// if the programmer starts with an Interface type for the first
|
||||
// (and following) bound(s) the implicit Object bound is considered
|
||||
// the first (that is 0:th) bound and type annotations start on
|
||||
// index 1.
|
||||
if (bounds.length > 0) {
|
||||
Type b0 = bounds[0];
|
||||
if (!(b0 instanceof Class<?>)) {
|
||||
startIndex = 1;
|
||||
} else {
|
||||
Class<?> c = (Class<?>)b0;
|
||||
if (c.isInterface()) {
|
||||
startIndex = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bounds.length; i++) {
|
||||
List<TypeAnnotation> l = new ArrayList<>(candidates.size());
|
||||
for (TypeAnnotation t : candidates) {
|
||||
TypeAnnotationTargetInfo tInfo = t.getTargetInfo();
|
||||
if (tInfo.getSecondaryIndex() == i + startIndex &&
|
||||
tInfo.getCount() == typeVarIndex) {
|
||||
l.add(t);
|
||||
}
|
||||
}
|
||||
res[i] = AnnotatedTypeFactory.buildAnnotatedType(bounds[i],
|
||||
loc,
|
||||
l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
|
||||
candidates.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
|
||||
(AnnotatedElement)decl);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return new AnnotatedType[0];
|
||||
}
|
||||
private static <D extends GenericDeclaration> List<TypeAnnotation> fetchBounds(D decl) {
|
||||
AnnotatedElement boundsDecl;
|
||||
TypeAnnotationTarget target;
|
||||
if (decl instanceof Class) {
|
||||
target = TypeAnnotationTarget.CLASS_TYPE_PARAMETER_BOUND;
|
||||
boundsDecl = (Class)decl;
|
||||
} else {
|
||||
target = TypeAnnotationTarget.METHOD_TYPE_PARAMETER_BOUND;
|
||||
boundsDecl = (Executable)decl;
|
||||
}
|
||||
return TypeAnnotation.filter(TypeAnnotationParser.parseAllTypeAnnotations(boundsDecl), target);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all type annotations on the declaration supplied. This is needed
|
||||
* when you go from for example an annotated return type on a method that
|
||||
* is a type variable declared on the class. In this case you need to
|
||||
* 'jump' to the decl of the class and parse all type annotations there to
|
||||
* find the ones that are applicable to the type variable.
|
||||
*/
|
||||
static TypeAnnotation[] parseAllTypeAnnotations(AnnotatedElement decl) {
|
||||
Class<?> container;
|
||||
byte[] rawBytes;
|
||||
JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess();
|
||||
if (decl instanceof Class) {
|
||||
container = (Class<?>)decl;
|
||||
rawBytes = javaLangAccess.getRawClassTypeAnnotations(container);
|
||||
} else if (decl instanceof Executable) {
|
||||
container = ((Executable)decl).getDeclaringClass();
|
||||
rawBytes = javaLangAccess.getRawExecutableTypeAnnotations((Executable)decl);
|
||||
} else {
|
||||
// Should not reach here. Assert?
|
||||
return EMPTY_TYPE_ANNOTATION_ARRAY;
|
||||
}
|
||||
return parseTypeAnnotations(rawBytes, javaLangAccess.getConstantPool(container),
|
||||
decl, container);
|
||||
}
|
||||
|
||||
/* Parse type annotations encoded as an array of bytes */
|
||||
private static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement baseDecl,
|
||||
Class<?> container) {
|
||||
if (rawAnnotations == null)
|
||||
return EMPTY_TYPE_ANNOTATION_ARRAY;
|
||||
|
||||
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
|
||||
int annotationCount = buf.getShort() & 0xFFFF;
|
||||
List<TypeAnnotation> typeAnnotations = new ArrayList<>(annotationCount);
|
||||
|
||||
// Parse each TypeAnnotation
|
||||
for (int i = 0; i < annotationCount; i++) {
|
||||
TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, container);
|
||||
if (ta != null)
|
||||
typeAnnotations.add(ta);
|
||||
}
|
||||
|
||||
return typeAnnotations.toArray(EMPTY_TYPE_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
// Helper
|
||||
static Map<Class<? extends Annotation>, Annotation> mapTypeAnnotations(TypeAnnotation[] typeAnnos) {
|
||||
Map<Class<? extends Annotation>, Annotation> result =
|
||||
new LinkedHashMap<>();
|
||||
for (TypeAnnotation t : typeAnnos) {
|
||||
Annotation a = t.getAnnotation();
|
||||
Class<? extends Annotation> klass = a.annotationType();
|
||||
AnnotationType type = AnnotationType.getInstance(klass);
|
||||
if (type.retention() == RetentionPolicy.RUNTIME)
|
||||
if (result.put(klass, a) != null)
|
||||
throw new AnnotationFormatError("Duplicate annotation for class: "+klass+": " + a);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Position codes
|
||||
// Regular type parameter annotations
|
||||
private static final byte CLASS_TYPE_PARAMETER = 0x00;
|
||||
private static final byte METHOD_TYPE_PARAMETER = 0x01;
|
||||
// Type Annotations outside method bodies
|
||||
private static final byte CLASS_EXTENDS = 0x10;
|
||||
private static final byte CLASS_TYPE_PARAMETER_BOUND = 0x11;
|
||||
private static final byte METHOD_TYPE_PARAMETER_BOUND = 0x12;
|
||||
private static final byte FIELD = 0x13;
|
||||
private static final byte METHOD_RETURN = 0x14;
|
||||
private static final byte METHOD_RECEIVER = 0x15;
|
||||
private static final byte METHOD_FORMAL_PARAMETER = 0x16;
|
||||
private static final byte THROWS = 0x17;
|
||||
// Type Annotations inside method bodies
|
||||
private static final byte LOCAL_VARIABLE = (byte)0x40;
|
||||
private static final byte RESOURCE_VARIABLE = (byte)0x41;
|
||||
private static final byte EXCEPTION_PARAMETER = (byte)0x42;
|
||||
private static final byte INSTANCEOF = (byte)0x43;
|
||||
private static final byte NEW = (byte)0x44;
|
||||
private static final byte CONSTRUCTOR_REFERENCE = (byte)0x45;
|
||||
private static final byte METHOD_REFERENCE = (byte)0x46;
|
||||
private static final byte CAST = (byte)0x47;
|
||||
private static final byte CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = (byte)0x48;
|
||||
private static final byte METHOD_INVOCATION_TYPE_ARGUMENT = (byte)0x49;
|
||||
private static final byte CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = (byte)0x4A;
|
||||
private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x4B;
|
||||
|
||||
private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement baseDecl,
|
||||
Class<?> container) {
|
||||
try {
|
||||
TypeAnnotationTargetInfo ti = parseTargetInfo(buf);
|
||||
LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf);
|
||||
Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, false);
|
||||
if (ti == null) // Inside a method for example
|
||||
return null;
|
||||
return new TypeAnnotation(ti, locationInfo, a, baseDecl);
|
||||
} catch (IllegalArgumentException | // Bad type in const pool at specified index
|
||||
BufferUnderflowException e) {
|
||||
throw new AnnotationFormatError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static TypeAnnotationTargetInfo parseTargetInfo(ByteBuffer buf) {
|
||||
int posCode = buf.get() & 0xFF;
|
||||
switch(posCode) {
|
||||
case CLASS_TYPE_PARAMETER:
|
||||
case METHOD_TYPE_PARAMETER: {
|
||||
int index = buf.get() & 0xFF;
|
||||
TypeAnnotationTargetInfo res;
|
||||
if (posCode == CLASS_TYPE_PARAMETER)
|
||||
res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_TYPE_PARAMETER,
|
||||
index);
|
||||
else
|
||||
res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_TYPE_PARAMETER,
|
||||
index);
|
||||
return res;
|
||||
} // unreachable break;
|
||||
case CLASS_EXTENDS: {
|
||||
short index = buf.getShort(); //needs to be signed
|
||||
if (index == -1) {
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_EXTENDS);
|
||||
} else if (index >= 0) {
|
||||
TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_IMPLEMENTS,
|
||||
index);
|
||||
return res;
|
||||
}} break;
|
||||
case CLASS_TYPE_PARAMETER_BOUND:
|
||||
return parse2ByteTarget(TypeAnnotationTarget.CLASS_TYPE_PARAMETER_BOUND, buf);
|
||||
case METHOD_TYPE_PARAMETER_BOUND:
|
||||
return parse2ByteTarget(TypeAnnotationTarget.METHOD_TYPE_PARAMETER_BOUND, buf);
|
||||
case FIELD:
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD);
|
||||
case METHOD_RETURN:
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN);
|
||||
case METHOD_RECEIVER:
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER);
|
||||
case METHOD_FORMAL_PARAMETER: {
|
||||
int index = buf.get() & 0xFF;
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_FORMAL_PARAMETER,
|
||||
index);
|
||||
} //unreachable break;
|
||||
case THROWS:
|
||||
return parseShortTarget(TypeAnnotationTarget.THROWS, buf);
|
||||
|
||||
/*
|
||||
* The ones below are inside method bodies, we don't care about them for core reflection
|
||||
* other than adjusting for them in the byte stream.
|
||||
*/
|
||||
case LOCAL_VARIABLE:
|
||||
case RESOURCE_VARIABLE:
|
||||
short length = buf.getShort();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
short offset = buf.getShort();
|
||||
short varLength = buf.getShort();
|
||||
short index = buf.getShort();
|
||||
}
|
||||
return null;
|
||||
case EXCEPTION_PARAMETER: {
|
||||
byte index = buf.get();
|
||||
}
|
||||
return null;
|
||||
case INSTANCEOF:
|
||||
case NEW:
|
||||
case CONSTRUCTOR_REFERENCE:
|
||||
case METHOD_REFERENCE: {
|
||||
short offset = buf.getShort();
|
||||
}
|
||||
return null;
|
||||
case CAST:
|
||||
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
|
||||
case METHOD_INVOCATION_TYPE_ARGUMENT:
|
||||
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
|
||||
case METHOD_REFERENCE_TYPE_ARGUMENT: {
|
||||
short offset = buf.getShort();
|
||||
byte index = buf.get();
|
||||
}
|
||||
return null;
|
||||
|
||||
default:
|
||||
// will throw error below
|
||||
break;
|
||||
}
|
||||
throw new AnnotationFormatError("Could not parse bytes for type annotations");
|
||||
}
|
||||
|
||||
private static TypeAnnotationTargetInfo parseShortTarget(TypeAnnotationTarget target, ByteBuffer buf) {
|
||||
int index = buf.getShort() & 0xFFFF;
|
||||
return new TypeAnnotationTargetInfo(target, index);
|
||||
}
|
||||
private static TypeAnnotationTargetInfo parse2ByteTarget(TypeAnnotationTarget target, ByteBuffer buf) {
|
||||
int count = buf.get() & 0xFF;
|
||||
int secondaryIndex = buf.get() & 0xFF;
|
||||
return new TypeAnnotationTargetInfo(target,
|
||||
count,
|
||||
secondaryIndex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, 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.*;
|
||||
|
||||
/**
|
||||
* ExceptionProxy for TypeNotPresentException.
|
||||
*
|
||||
* @author Josh Bloch
|
||||
* @since 1.5
|
||||
*/
|
||||
public class TypeNotPresentExceptionProxy extends ExceptionProxy {
|
||||
private static final long serialVersionUID = 5565925172427947573L;
|
||||
String typeName;
|
||||
Throwable cause;
|
||||
|
||||
public TypeNotPresentExceptionProxy(String typeName, Throwable cause) {
|
||||
this.typeName = typeName;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
protected RuntimeException generateException() {
|
||||
return new TypeNotPresentException(typeName, cause);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user