8004698: Implement Core Reflection for Type Annotations

Reviewed-by: darcy
This commit is contained in:
Joel Borggrén-Franck 2013-01-29 10:32:49 +01:00
parent c2419823c8
commit b29b479461
25 changed files with 2106 additions and 29 deletions

@ -29,12 +29,14 @@ import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Member;
import java.lang.reflect.Field;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.AnnotatedType;
import java.lang.ref.SoftReference;
import java.io.InputStream;
import java.io.ObjectStreamField;
@ -2325,6 +2327,11 @@ public final
// Annotations handling
private native byte[] getRawAnnotations();
// Since 1.8
native byte[] getRawTypeAnnotations();
static byte[] getExecutableTypeAnnotationBytes(Executable ex) {
return getReflectionFactory().getExecutableTypeAnnotationBytes(ex);
}
native ConstantPool getConstantPool();
@ -3196,4 +3203,53 @@ public final
* Maintained by the ClassValue class.
*/
transient ClassValue.ClassValueMap classValueMap;
/**
* Returns an AnnotatedType object that represents the use of a type to specify
* the superclass of the entity represented by this Class. (The <em>use</em> of type
* Foo to specify the superclass in '... extends Foo' is distinct from the
* <em>declaration</em> of type Foo.)
*
* If this Class represents a class type whose declaration does not explicitly
* indicate an annotated superclass, the return value is null.
*
* If this Class represents either the Object class, an interface type, an
* array type, a primitive type, or void, the return value is null.
*
* @since 1.8
*/
public AnnotatedType getAnnotatedSuperclass() {
return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this);
}
/**
* Returns an array of AnnotatedType objects that represent the use of types to
* specify superinterfaces of the entity represented by this Class. (The <em>use</em>
* of type Foo to specify a superinterface in '... implements Foo' is
* distinct from the <em>declaration</em> of type Foo.)
*
* If this Class represents a class, the return value is an array
* containing objects representing the uses of interface types to specify
* interfaces implemented by the class. The order of the objects in the
* array corresponds to the order of the interface types used in the
* 'implements' clause of the declaration of this Class.
*
* If this Class represents an interface, the return value is an array
* containing objects representing the uses of interface types to specify
* interfaces directly extended by the interface. The order of the objects in
* the array corresponds to the order of the interface types used in the
* 'extends' clause of the declaration of this Class.
*
* If this Class represents a class or interface whose declaration does not
* explicitly indicate any annotated superinterfaces, the return value is an
* array of length 0.
*
* If this Class represents either the Object class, an array type, a
* primitive type, or void, the return value is an array of length 0.
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedInterfaces() {
return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@ -26,6 +26,7 @@ package java.lang;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.util.Properties;
import java.util.PropertyPermission;
import java.util.StringTokenizer;
@ -1199,6 +1200,12 @@ public final class System {
public <A extends Annotation> A getDirectDeclaredAnnotation(Class<?> klass, Class<A> anno) {
return klass.getDirectDeclaredAnnotation(anno);
}
public byte[] getRawClassTypeAnnotations(Class<?> klass) {
return klass.getRawTypeAnnotations();
}
public byte[] getRawExecutableTypeAnnotations(Executable executable) {
return Class.getExecutableTypeAnnotationBytes(executable);
}
public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();

@ -0,0 +1,43 @@
/*
* 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 java.lang.reflect;
/**
* AnnotatedArrayType represents the use of an array type, whose component
* type may itself represent the annotated use of a type.
*
* @since 1.8
*/
public interface AnnotatedArrayType extends AnnotatedType {
/**
* Returns the annotated generic component type of this array type.
*
* @return the annotated generic component type of this array type
*/
AnnotatedType getAnnotatedGenericComponentType();
}

@ -0,0 +1,42 @@
/*
* 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 java.lang.reflect;
/**
* AnnotatedParameterizedType represents the use of a parameterized type,
* whose type arguments may themselves represent annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedParameterizedType extends AnnotatedType {
/**
* Returns the annotated actual type arguments of this parameterized type.
*
* @return the annotated actual type arguments of this parameterized type
*/
AnnotatedType[] getAnnotatedActualTypeArguments();
}

@ -0,0 +1,44 @@
/*
* 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 java.lang.reflect;
/**
* AnnotatedType represents the annotated use of a type in the program
* currently running in this VM. The use may be of any type in the Java
* programming language, including an array type, a parameterized type, a type
* variable, or a wildcard type.
*
* @since 1.8
*/
public interface AnnotatedType extends AnnotatedElement {
/**
* Returns the underlying type that this annotated type represents.
*
* @return the type this annotated type represents
*/
public Type getType();
}

@ -0,0 +1,43 @@
/*
* 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 java.lang.reflect;
/**
* AnnotatedTypeVariable represents the use of a type variable, whose
* declaration may have bounds which themselves represent annotated uses of
* types.
*
* @since 1.8
*/
public interface AnnotatedTypeVariable extends AnnotatedType {
/**
* Returns the annotated bounds of this type variable.
*
* @return the annotated bounds of this type variable
*/
AnnotatedType[] getAnnotatedBounds();
}

@ -0,0 +1,49 @@
/*
* 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 java.lang.reflect;
/**
* AnnotatedWildcardType represents the use of a wildcard type argument, whose
* upper or lower bounds may themselves represent annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedWildcardType extends AnnotatedType {
/**
* Returns the annotated lower bounds of this wildcard type.
*
* @return the annotated lower bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedLowerBounds();
/**
* Returns the annotated upper bounds of this wildcard type.
*
* @return the annotated upper bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedUpperBounds();
}

@ -154,6 +154,10 @@ public final class Constructor<T> extends Executable {
byte[] getAnnotationBytes() {
return annotations;
}
@Override
byte[] getTypeAnnotationBytes() {
return typeAnnotations;
}
/**
* {@inheritDoc}
@ -523,4 +527,12 @@ public final class Constructor<T> extends Executable {
}
}
}
/**
* {@inheritDoc}
* @since 1.8
*/
public AnnotatedType getAnnotatedReturnType() {
return getAnnotatedReturnType0(getDeclaringClass());
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -31,6 +31,8 @@ import java.util.Map;
import java.util.Objects;
import sun.reflect.annotation.AnnotationParser;
import sun.reflect.annotation.AnnotationSupport;
import sun.reflect.annotation.TypeAnnotationParser;
import sun.reflect.annotation.TypeAnnotation;
import sun.reflect.generics.repository.ConstructorRepository;
/**
@ -50,6 +52,7 @@ public abstract class Executable extends AccessibleObject
* Accessor method to allow code sharing
*/
abstract byte[] getAnnotationBytes();
abstract byte[] getTypeAnnotationBytes();
/**
* Does the Executable have generic information.
@ -470,4 +473,86 @@ public abstract class Executable extends AccessibleObject
return declaredAnnotations;
}
/* Helper for subclasses of Executable.
*
* Returns an AnnotatedType object that represents the use of a type to
* specify the return type of the method/constructor represented by this
* Executable.
*
* @since 1.8
*/
AnnotatedType getAnnotatedReturnType0(Type returnType) {
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
getDeclaringClass(),
returnType,
TypeAnnotation.TypeAnnotationTarget.METHOD_RETURN_TYPE);
}
/**
* Returns an AnnotatedType object that represents the use of a type to
* specify the receiver type of the method/constructor represented by this
* Executable. The receiver type of a method/constructor is available only
* if the method/constructor declares a formal parameter called 'this'.
*
* Returns null if this Executable represents a constructor or instance
* method that either declares no formal parameter called 'this', or
* declares a formal parameter called 'this' with no annotations on its
* type.
*
* Returns null if this Executable represents a static method.
*
* @since 1.8
*/
public AnnotatedType getAnnotatedReceiverType() {
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
getDeclaringClass(),
getDeclaringClass(),
TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER_TYPE);
}
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to specify formal parameter types of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the formal parameter types in the
* declaration of the method/constructor.
*
* Returns an array of length 0 if the method/constructor declares no
* parameters.
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedParameterTypes() {
throw new UnsupportedOperationException("Not yet");
}
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to specify the declared exceptions of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the exception types in the declaration of
* the method/constructor.
*
* Returns an array of length 0 if the method/constructor declares no
* exceptions.
*
* @since 1.8
*/
public AnnotatedType[] getAnnotatedExceptionTypes() {
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
getDeclaringClass(),
getGenericExceptionTypes(),
TypeAnnotation.TypeAnnotationTarget.THROWS);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 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
@ -36,7 +36,8 @@ import java.util.Map;
import java.util.Objects;
import sun.reflect.annotation.AnnotationParser;
import sun.reflect.annotation.AnnotationSupport;
import sun.reflect.annotation.TypeAnnotation;
import sun.reflect.annotation.TypeAnnotationParser;
/**
* A {@code Field} provides information about, and dynamic access to, a
@ -1053,4 +1054,20 @@ class Field extends AccessibleObject implements Member {
}
return declaredAnnotations;
}
/**
* Returns an AnnotatedType object that represents the use of a type to specify
* the declared type of the field represented by this Field.
*
* @since 1.8
*/
public AnnotatedType getAnnotatedType() {
return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
this,
getDeclaringClass(),
getGenericType(),
TypeAnnotation.TypeAnnotationTarget.FIELD_TYPE);
}
}

@ -165,6 +165,10 @@ public final class Method extends Executable {
byte[] getAnnotationBytes() {
return annotations;
}
@Override
byte[] getTypeAnnotationBytes() {
return typeAnnotations;
}
/**
* {@inheritDoc}
@ -621,6 +625,14 @@ public final class Method extends Executable {
return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations);
}
/**
* {@inheritDoc}
* @since 1.8
*/
public AnnotatedType getAnnotatedReturnType() {
return getAnnotatedReturnType0(getGenericReturnType());
}
@Override
void handleParameterNumberMismatch(int resultLength, int numParameters) {
throw new AnnotationFormatError("Parameter annotations don't match number of parameters");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -128,6 +128,10 @@ class ReflectAccess implements sun.reflect.LangReflectAccess {
return c.getRawParameterAnnotations();
}
public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
return ex.getTypeAnnotationBytes();
}
//
// Copying routines, needed to quickly fabricate new Field,
// Method, and Constructor objects from templates

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* 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
@ -86,4 +86,16 @@ public interface TypeVariable<D extends GenericDeclaration> extends Type, Annota
* @return the name of this type variable, as it appears in the source code
*/
String getName();
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to denote the upper bounds of the type parameter represented by
* this TypeVariable. The order of the objects in the array corresponds to
* the order of the bounds in the declaration of the type parameter.
*
* Returns an array of length 0 if the type parameter declares no bounds.
*
* @since 1.8
*/
AnnotatedType[] getAnnotatedBounds();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* 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
@ -26,6 +26,7 @@
package sun.misc;
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import sun.reflect.ConstantPool;
import sun.reflect.annotation.AnnotationType;
import sun.nio.ch.Interruptible;
@ -46,6 +47,18 @@ public interface JavaLangAccess {
*/
AnnotationType getAnnotationType(Class<?> klass);
/**
* Get the array of bytes that is the class-file representation
* of this Class' type annotations.
*/
byte[] getRawClassTypeAnnotations(Class<?> klass);
/**
* Get the array of bytes that is the class-file representation
* of this Executable's type annotations.
*/
byte[] getRawExecutableTypeAnnotations(Executable executable);
/**
* Returns the elements of an enum class or null if the
* Class object does not represent an enum type;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -81,6 +81,9 @@ public interface LangReflectAccess {
public void setConstructorAccessor(Constructor<?> c,
ConstructorAccessor accessor);
/** Gets the byte[] that encodes TypeAnnotations on an Executable. */
public byte[] getExecutableTypeAnnotationBytes(Executable ex);
/** Gets the "slot" field from a Constructor (used for serialization) */
public int getConstructorSlot(Constructor<?> c);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -26,6 +26,7 @@
package sun.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
@ -314,6 +315,12 @@ public class ReflectionFactory {
return langReflectAccess().copyConstructor(arg);
}
/** Gets the byte[] that encodes TypeAnnotations on an executable.
*/
public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
return langReflectAccess().getExecutableTypeAnnotationBytes(ex);
}
//--------------------------------------------------------------------------
//
// Routines used by serialization

@ -0,0 +1,320 @@
/*
* 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 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;
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);
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 boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
return annotations.get(annotation) != null;
}
@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[] getAnnotations(Class<T> annotation) {
return getDeclaredAnnotations(annotation);
}
@Override
public Annotation[] getDeclaredAnnotations() {
return annotations.values().toArray(new Annotation[0]);
}
@Override
@SuppressWarnings("unchecked")
public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
return (T)annotations.get(annotation);
}
@Override
public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotation) {
return AnnotationSupport.getMultipleAnnotations(annotations, annotation);
}
// AnnotatedType
@Override
public Type getType() {
return type;
}
// Implementation details
LocationInfo getLocation() {
return location;
}
TypeAnnotation[] getTypeAnnotations() {
return allOnSameTargetTypeAnnotations;
}
AnnotatedElement getDecl() {
return decl;
}
}
private static 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 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 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 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;
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* 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
@ -188,7 +188,7 @@ public class AnnotationParser {
* available at runtime
*/
@SuppressWarnings("unchecked")
private static Annotation parseAnnotation(ByteBuffer buf,
static Annotation parseAnnotation(ByteBuffer buf,
ConstantPool constPool,
Class<?> container,
boolean exceptionOnMissingAnnotationClass) {

@ -0,0 +1,227 @@
/*
* 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 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,
CLASS_PARAMETER_BOUND,
METHOD_PARAMETER_BOUND,
METHOD_RETURN_TYPE,
METHOD_RECEIVER_TYPE,
FIELD_TYPE,
THROWS;
}
public static 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 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();
if (depth == 0)
return BASE_LOCATION;
Location[] locations = new Location[depth];
for (int i = 0; i < depth; i++) {
byte tag = buf.get();
byte index = buf.get();
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, (byte)0);
}
public LocationInfo pushInner() {
return pushLocation((byte)1, (byte)0);
}
public LocationInfo pushWildcard() {
return pushLocation((byte) 2, (byte) 0);
}
public LocationInfo pushTypeArg(byte index) {
return pushLocation((byte) 3, index);
}
public LocationInfo pushLocation(byte tag, byte 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, index);
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 class Location {
public final byte tag;
public final byte index;
boolean isSameLocation(Location other) {
return tag == other.tag && index == other.index;
}
public Location(byte tag, byte index) {
this.tag = tag;
this.index = index;
}
}
}
@Override
public String toString() {
return annotation.toString() + " with Targetnfo: " +
targetInfo.toString() + " on base declaration: " +
baseDeclaration.toString();
}
}

@ -0,0 +1,491 @@
/*
* 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 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 dclaration 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(new TypeAnnotation[0]);
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];
if (list != null) {
TypeAnnotation[] typeAnnotations = list.toArray(new TypeAnnotation[0]);
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) {
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
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];
Arrays.fill(res, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE);
// 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(new TypeAnnotation[0]),
candidates.toArray(new TypeAnnotation[0]),
(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_PARAMETER_BOUND;
boundsDecl = (Class)decl;
} else {
target = TypeAnnotationTarget.METHOD_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 CAST = (byte)0x43;
private static final byte INSTANCEOF = (byte)0x44;
private static final byte NEW = (byte)0x45;
private static final byte CONSTRUCTOR_REFERENCE_RECEIVER = (byte)0x46;
private static final byte METHOD_REFERENCE_RECEIVER = (byte)0x47;
private static final byte LAMBDA_FORMAL_PARAMETER = (byte)0x48;
private static final byte METHOD_REFERENCE = (byte)0x49;
private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x50;
private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf,
ConstantPool cp,
AnnotatedElement baseDecl,
Class<?> container) {
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);
}
private static TypeAnnotationTargetInfo parseTargetInfo(ByteBuffer buf) {
byte posCode = buf.get();
switch(posCode) {
case CLASS_TYPE_PARAMETER:
case METHOD_TYPE_PARAMETER: {
byte index = buf.get();
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();
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_PARAMETER_BOUND, buf);
case METHOD_TYPE_PARAMETER_BOUND:
return parse2ByteTarget(TypeAnnotationTarget.METHOD_PARAMETER_BOUND, buf);
case FIELD:
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD_TYPE);
case METHOD_RETURN:
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN_TYPE);
case METHOD_RECEIVER:
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER_TYPE);
case METHOD_FORMAL_PARAMETER: {
// Todo
byte index = buf.get();
} 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();
}
break;
case EXCEPTION_PARAMETER: {
byte index = buf.get();
} break;
case CAST:
case INSTANCEOF:
case NEW: {
short offset = buf.getShort();
} break;
case CONSTRUCTOR_REFERENCE_RECEIVER:
case METHOD_REFERENCE_RECEIVER: {
short offset = buf.getShort();
byte index = buf.get();
} break;
case LAMBDA_FORMAL_PARAMETER: {
byte index = buf.get();
} break;
case METHOD_REFERENCE:
// This one isn't in the spec yet
break;
case METHOD_REFERENCE_TYPE_ARGUMENT: {
short offset = buf.getShort();
byte index = buf.get();
} break;
default:
// will throw error below
break;
}
throw new AnnotationFormatError("Could not parse bytes for type annotations");
}
private static TypeAnnotationTargetInfo parseShortTarget(TypeAnnotationTarget target, ByteBuffer buf) {
short index = buf.getShort();
return new TypeAnnotationTargetInfo(target, index);
}
private static TypeAnnotationTargetInfo parse2ByteTarget(TypeAnnotationTarget target, ByteBuffer buf) {
byte count = buf.get();
byte secondaryIndex = buf.get();
return new TypeAnnotationTargetInfo(target,
count,
secondaryIndex);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,13 +25,18 @@
package sun.reflect.generics.reflectiveObjects;
import java.lang.annotation.Annotation;
import java.lang.annotation.*;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Array;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import sun.reflect.annotation.AnnotationSupport;
import sun.reflect.annotation.TypeAnnotationParser;
import sun.reflect.annotation.AnnotationType;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.tree.FieldTypeSignature;
import sun.reflect.generics.visitor.Reifier;
@ -182,45 +187,75 @@ public class TypeVariableImpl<D extends GenericDeclaration>
return genericDeclaration.hashCode() ^ name.hashCode();
}
// Currently vacuous implementations of AnnotatedElement methods.
// Implementations of AnnotatedElement methods.
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
Objects.requireNonNull(annotationClass);
return false;
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return null;
// T is an Annotation type, the return value of get will be an annotation
return (T)mapAnnotations(getAnnotations()).get(annotationClass);
}
public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return null;
return getAnnotation(annotationClass);
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
// safe because annotationClass is the class for T
return (T[])Array.newInstance(annotationClass, 0);
return AnnotationSupport.getMultipleAnnotations(mapAnnotations(getAnnotations()), annotationClass);
}
@SuppressWarnings("unchecked")
public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
// safe because annotationClass is the class for T
return (T[])Array.newInstance(annotationClass, 0);
return getAnnotations(annotationClass);
}
public Annotation[] getAnnotations() {
// Since zero-length, don't need defensive clone
return EMPTY_ANNOTATION_ARRAY;
int myIndex = typeVarIndex();
if (myIndex < 0)
throw new AssertionError("Index must be non-negative.");
return TypeAnnotationParser.parseTypeVariableAnnotations(getGenericDeclaration(), myIndex);
}
public Annotation[] getDeclaredAnnotations() {
// Since zero-length, don't need defensive clone
return EMPTY_ANNOTATION_ARRAY;
return getAnnotations();
}
public AnnotatedType[] getAnnotatedBounds() {
return TypeAnnotationParser.parseAnnotatedBounds(getBounds(),
getGenericDeclaration(),
typeVarIndex());
}
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
// Helpers for annotation methods
private int typeVarIndex() {
TypeVariable<?>[] tVars = getGenericDeclaration().getTypeParameters();
int i = -1;
for (TypeVariable<?> v : tVars) {
i++;
if (equals(v))
return i;
}
return -1;
}
private static Map<Class<? extends Annotation>, Annotation> mapAnnotations(Annotation[] annos) {
Map<Class<? extends Annotation>, Annotation> result =
new LinkedHashMap<>();
for (Annotation a : annos) {
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;
}
}

@ -465,6 +465,12 @@ JVM_GetClassSignature(JNIEnv *env, jclass cls);
JNIEXPORT jbyteArray JNICALL
JVM_GetClassAnnotations(JNIEnv *env, jclass cls);
/* Type use annotations support (JDK 1.8) */
JNIEXPORT jbyteArray JNICALL
JVM_GetClassTypeAnnotations(JNIEnv *env, jclass cls);
/*
* New (JDK 1.4) reflection implementation
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@ -75,7 +75,8 @@ static JNINativeMethod methods[] = {
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
{"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus},
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo}
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo},
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
};
#undef OBJ

@ -0,0 +1,428 @@
/*
* 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.
*
* 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.
*/
/*
* @test
* @bug 8004698
* @summary Unit test for type annotations
*/
import java.util.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
public class TypeAnnotationReflection {
public static void main(String[] args) throws Exception {
testSuper();
testInterfaces();
testReturnType();
testNested();
testArray();
testRunException();
testClassTypeVarBounds();
testMethodTypeVarBounds();
testFields();
testClassTypeVar();
testMethodTypeVar();
testParameterizedType();
testNestedParameterizedType();
testWildcardType();
}
private static void check(boolean b) {
if (!b)
throw new RuntimeException();
}
private static void testSuper() throws Exception {
check(Object.class.getAnnotatedSuperclass().getAnnotations().length == 0);
check(Class.class.getAnnotatedSuperclass().getAnnotations().length == 0);
AnnotatedType a;
a = TestClassArray.class.getAnnotatedSuperclass();
Annotation[] annos = a.getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("extends"));
check(((TypeAnno2)annos[1]).value().equals("extends2"));
}
private static void testInterfaces() throws Exception {
AnnotatedType[] as;
as = TestClassArray.class.getAnnotatedInterfaces();
check(as.length == 3);
check(as[1].getAnnotations().length == 0);
Annotation[] annos;
annos = as[0].getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("implements serializable"));
check(((TypeAnno2)annos[1]).value().equals("implements2 serializable"));
annos = as[2].getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("implements cloneable"));
check(((TypeAnno2)annos[1]).value().equals("implements2 cloneable"));
}
private static void testReturnType() throws Exception {
Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null);
Annotation[] annos = m.getAnnotatedReturnType().getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("return1"));
}
private static void testNested() throws Exception {
Method m = TestClassNested.class.getDeclaredMethod("foo", (Class<?>[])null);
Annotation[] annos = m.getAnnotatedReturnType().getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("array"));
AnnotatedType t = m.getAnnotatedReturnType();
t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
annos = t.getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("Inner"));
}
private static void testArray() throws Exception {
Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null);
AnnotatedArrayType t = (AnnotatedArrayType) m.getAnnotatedReturnType();
Annotation[] annos = t.getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("return1"));
t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType();
annos = t.getAnnotations();
check(annos.length == 0);
t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType();
annos = t.getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("return3"));
AnnotatedType tt = t.getAnnotatedGenericComponentType();
check(!(tt instanceof AnnotatedArrayType));
annos = tt.getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("return4"));
}
private static void testRunException() throws Exception {
Method m = TestClassException.class.getDeclaredMethod("foo", (Class<?>[])null);
AnnotatedType[] ts = m.getAnnotatedExceptionTypes();
check(ts.length == 3);
AnnotatedType t;
Annotation[] annos;
t = ts[0];
annos = t.getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("RE"));
check(((TypeAnno2)annos[1]).value().equals("RE2"));
t = ts[1];
annos = t.getAnnotations();
check(annos.length == 0);
t = ts[2];
annos = t.getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("AIOOBE"));
}
private static void testClassTypeVarBounds() throws Exception {
Method m = TestClassTypeVarAndField.class.getDeclaredMethod("foo", (Class<?>[])null);
AnnotatedType ret = m.getAnnotatedReturnType();
Annotation[] annos = ret.getAnnotations();
check(annos.length == 2);
AnnotatedType[] annotatedBounds = ((AnnotatedTypeVariable)ret).getAnnotatedBounds();
check(annotatedBounds.length == 2);
annos = annotatedBounds[0].getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("Object1"));
annos = annotatedBounds[1].getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("Runnable1"));
check(((TypeAnno2)annos[1]).value().equals("Runnable2"));
}
private static void testMethodTypeVarBounds() throws Exception {
Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null);
AnnotatedType ret2 = m2.getAnnotatedReturnType();
AnnotatedType[] annotatedBounds2 = ((AnnotatedTypeVariable)ret2).getAnnotatedBounds();
check(annotatedBounds2.length == 1);
Annotation[] annos = annotatedBounds2[0].getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("M Runnable"));
}
private static void testFields() throws Exception {
Field f1 = TestClassTypeVarAndField.class.getDeclaredField("field1");
AnnotatedType at;
Annotation[] annos;
at = f1.getAnnotatedType();
annos = at.getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("T1 field"));
check(((TypeAnno2)annos[1]).value().equals("T2 field"));
Field f2 = TestClassTypeVarAndField.class.getDeclaredField("field2");
at = f2.getAnnotatedType();
annos = at.getAnnotations();
check(annos.length == 0);
Field f3 = TestClassTypeVarAndField.class.getDeclaredField("field3");
at = f3.getAnnotatedType();
annos = at.getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("Object field"));
}
private static void testClassTypeVar() throws Exception {
TypeVariable[] typeVars = TestClassTypeVarAndField.class.getTypeParameters();
Annotation[] annos;
check(typeVars.length == 2);
// First TypeVar
AnnotatedType[] annotatedBounds = typeVars[0].getAnnotatedBounds();
check(annotatedBounds.length == 2);
annos = annotatedBounds[0].getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("Object1"));
annos = annotatedBounds[1].getAnnotations();
check(annos.length == 2);
check(annos[0].annotationType().equals(TypeAnno.class));
check(annos[1].annotationType().equals(TypeAnno2.class));
check(((TypeAnno)annos[0]).value().equals("Runnable1"));
check(((TypeAnno2)annos[1]).value().equals("Runnable2"));
// second TypeVar regular anno
Annotation[] regularAnnos = typeVars[1].getAnnotations();
check(regularAnnos.length == 1);
check(typeVars[1].getAnnotation(TypeAnno.class).value().equals("EE"));
// second TypeVar
annotatedBounds = typeVars[1].getAnnotatedBounds();
check(annotatedBounds.length == 1);
annos = annotatedBounds[0].getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno2.class));
check(((TypeAnno2)annos[0]).value().equals("EEBound"));
}
private static void testMethodTypeVar() throws Exception {
Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null);
TypeVariable[] t = m2.getTypeParameters();
check(t.length == 1);
Annotation[] annos = t[0].getAnnotations();
check(annos.length == 0);
AnnotatedType[] annotatedBounds2 = t[0].getAnnotatedBounds();
check(annotatedBounds2.length == 1);
annos = annotatedBounds2[0].getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("M Runnable"));
// Second method
m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo3", (Class<?>[])null);
t = m2.getTypeParameters();
check(t.length == 1);
annos = t[0].getAnnotations();
check(annos.length == 1);
check(annos[0].annotationType().equals(TypeAnno.class));
check(((TypeAnno)annos[0]).value().equals("K"));
annotatedBounds2 = t[0].getAnnotatedBounds();
check(annotatedBounds2.length == 1);
annos = annotatedBounds2[0].getAnnotations();
check(annos.length == 0);
}
private static void testParameterizedType() {
// Base
AnnotatedType[] as;
as = TestParameterizedType.class.getAnnotatedInterfaces();
check(as.length == 1);
check(as[0].getAnnotations().length == 1);
check(as[0].getAnnotation(TypeAnno.class).value().equals("M"));
Annotation[] annos;
as = ((AnnotatedParameterizedType)as[0]).getAnnotatedActualTypeArguments();
check(as.length == 2);
annos = as[0].getAnnotations();
check(annos.length == 1);
check(as[0].getAnnotation(TypeAnno.class).value().equals("S"));
check(as[0].getAnnotation(TypeAnno2.class) == null);
annos = as[1].getAnnotations();
check(annos.length == 2);
check(((TypeAnno)annos[0]).value().equals("I"));
check(as[1].getAnnotation(TypeAnno2.class).value().equals("I2"));
}
private static void testNestedParameterizedType() throws Exception {
Method m = TestParameterizedType.class.getDeclaredMethod("foo2", (Class<?>[])null);
AnnotatedType ret = m.getAnnotatedReturnType();
Annotation[] annos;
annos = ret.getAnnotations();
check(annos.length == 1);
check(((TypeAnno)annos[0]).value().equals("I"));
AnnotatedType[] args = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments();
check(args.length == 1);
annos = args[0].getAnnotations();
check(annos.length == 2);
check(((TypeAnno)annos[0]).value().equals("I1"));
check(args[0].getAnnotation(TypeAnno2.class).value().equals("I2"));
}
private static void testWildcardType() throws Exception {
Method m = TestWildcardType.class.getDeclaredMethod("foo", (Class<?>[])null);
AnnotatedType ret = m.getAnnotatedReturnType();
AnnotatedType[] t;
t = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments();
check(t.length == 1);
ret = t[0];
Field f = TestWildcardType.class.getDeclaredField("f1");
AnnotatedWildcardType w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
t = w.getAnnotatedLowerBounds();
check(t.length == 0);
t = w.getAnnotatedUpperBounds();
check(t.length == 1);
Annotation[] annos;
annos = t[0].getAnnotations();
check(annos.length == 1);
check(((TypeAnno)annos[0]).value().equals("2"));
f = TestWildcardType.class.getDeclaredField("f2");
w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
t = w.getAnnotatedUpperBounds();
check(t.length == 0);
t = w.getAnnotatedLowerBounds();
check(t.length == 1);
}
}
abstract class TestWildcardType {
public <T> List<? super T> foo() { return null;}
public Class<@TypeAnno("1") ? extends @TypeAnno("2") Annotation> f1;
public Class<@TypeAnno("3") ? super @TypeAnno("4") Annotation> f2;
}
abstract class TestParameterizedType implements @TypeAnno("M") Map<@TypeAnno("S")String, @TypeAnno("I") @TypeAnno2("I2")Integer> {
public ParameterizedOuter<String>.ParameterizedInner<Integer> foo() {return null;}
public @TypeAnno("O") ParameterizedOuter<@TypeAnno("S1") @TypeAnno2("S2") String>.
@TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() {
return null;
}
}
class ParameterizedOuter <T> {
class ParameterizedInner <U> {}
}
abstract class TestClassArray extends @TypeAnno("extends") @TypeAnno2("extends2") Object
implements @TypeAnno("implements serializable") @TypeAnno2("implements2 serializable") Serializable,
Readable,
@TypeAnno("implements cloneable") @TypeAnno2("implements2 cloneable") Cloneable {
public @TypeAnno("return4") Object @TypeAnno("return1") [][] @TypeAnno("return3")[] foo() { return null; }
}
abstract class TestClassNested {
public @TypeAnno("Outer") Outer.@TypeAnno("Inner")Inner @TypeAnno("array")[] foo() { return null; }
}
class Outer {
class Inner {
}
}
abstract class TestClassException {
public Object foo() throws @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException,
NullPointerException,
@TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException {
return null;
}
}
abstract class TestClassTypeVarAndField <T extends @TypeAnno("Object1") Object
& @TypeAnno("Runnable1") @TypeAnno2("Runnable2") Runnable,
@TypeAnno("EE")EE extends @TypeAnno2("EEBound") Runnable > {
@TypeAnno("T1 field") @TypeAnno2("T2 field") T field1;
T field2;
@TypeAnno("Object field") Object field3;
public @TypeAnno("t1") @TypeAnno2("t2") T foo(){ return null; }
public <M extends @TypeAnno("M Runnable") Runnable> M foo2() {return null;}
public <@TypeAnno("K") K extends Cloneable> K foo3() {return null;}
}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface TypeAnno {
String value();
}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface TypeAnno2 {
String value();
}

@ -0,0 +1,120 @@
/*
* 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.
*
* 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.
*/
/*
* @test
* @bug 8004698
* @summary Unit test for annotations on TypeVariables
*/
import java.util.*;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
public class TypeParamAnnotation {
public static void main(String[] args) throws Exception {
testOnClass();
testOnMethod();
testGetAnno();
testGetAnnos();
}
private static void check(boolean b) {
if (!b)
throw new RuntimeException();
}
private static void testOnClass() {
TypeVariable<?>[] ts = TypeParam.class.getTypeParameters();
check(ts.length == 3);
Annotation[] as;
as = ts[0].getAnnotations();
check(as.length == 2);
check(((ParamAnno)as[0]).value().equals("t"));
check(((ParamAnno2)as[1]).value() == 1);
as = ts[1].getAnnotations();
check(as.length == 0);
as = ts[2].getAnnotations();
check(as.length == 2);
check(((ParamAnno)as[0]).value().equals("v"));
check(((ParamAnno2)as[1]).value() == 2);
}
private static void testOnMethod() throws Exception {
TypeVariable<?>[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters();
check(ts.length == 3);
Annotation[] as;
as = ts[0].getAnnotations();
check(as.length == 2);
check(((ParamAnno)as[0]).value().equals("x"));
check(((ParamAnno2)as[1]).value() == 3);
as = ts[1].getAnnotations();
check(as.length == 0);
as = ts[2].getAnnotations();
check(as.length == 2);
check(((ParamAnno)as[0]).value().equals("z"));
check(((ParamAnno2)as[1]).value() == 4);
}
private static void testGetAnno() {
TypeVariable<?>[] ts = TypeParam.class.getTypeParameters();
ParamAnno a;
a = ts[0].getAnnotation(ParamAnno.class);
check(a.value().equals("t"));
}
private static void testGetAnnos() throws Exception {
TypeVariable<?>[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters();
ParamAnno2[] as;
as = ts[0].getAnnotations(ParamAnno2.class);
check(as.length == 1);
check(as[0].value() == 3);
}
}
class TypeParam <@ParamAnno("t") @ParamAnno2(1) T,
U,
@ParamAnno("v") @ParamAnno2(2) V extends Runnable> {
public <@ParamAnno("x") @ParamAnno2(3) X,
Y,
@ParamAnno("z") @ParamAnno2(4) Z extends Cloneable> void foo() {}
}
@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface ParamAnno {
String value();
}
@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@interface ParamAnno2 {
int value();
}