--- a/jdk/src/share/classes/java/lang/Class.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/Class.java Tue Jan 29 10:32:49 2013 +0100
@@ -29,12 +29,14 @@
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 @@
// 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 @@
* 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);
+ }
+}
--- a/jdk/src/share/classes/java/lang/System.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/System.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
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 <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();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedArrayType.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedType.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java Tue Jan 29 10:32:49 2013 +0100
@@ -154,6 +154,10 @@
byte[] getAnnotationBytes() {
return annotations;
}
+ @Override
+ byte[] getTypeAnnotationBytes() {
+ return typeAnnotations;
+ }
/**
* {@inheritDoc}
@@ -523,4 +527,12 @@
}
}
}
+
+ /**
+ * {@inheritDoc}
+ * @since 1.8
+ */
+ public AnnotatedType getAnnotatedReturnType() {
+ return getAnnotatedReturnType0(getDeclaringClass());
+ }
}
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java Tue Jan 29 10:32:49 2013 +0100
@@ -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.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 @@
* Accessor method to allow code sharing
*/
abstract byte[] getAnnotationBytes();
+ abstract byte[] getTypeAnnotationBytes();
/**
* Does the Executable have generic information.
@@ -470,4 +473,86 @@
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);
+ }
+
}
--- a/jdk/src/share/classes/java/lang/reflect/Field.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java Tue Jan 29 10:32:49 2013 +0100
@@ -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.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 @@
}
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);
}
+}
--- a/jdk/src/share/classes/java/lang/reflect/Method.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java Tue Jan 29 10:32:49 2013 +0100
@@ -165,6 +165,10 @@
byte[] getAnnotationBytes() {
return annotations;
}
+ @Override
+ byte[] getTypeAnnotationBytes() {
+ return typeAnnotations;
+ }
/**
* {@inheritDoc}
@@ -621,6 +625,14 @@
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");
--- a/jdk/src/share/classes/java/lang/reflect/ReflectAccess.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/ReflectAccess.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
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
--- a/jdk/src/share/classes/java/lang/reflect/TypeVariable.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/TypeVariable.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
* @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();
}
--- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java Tue Jan 29 10:32:49 2013 +0100
@@ -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;
@@ -47,6 +48,18 @@
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;
* the result is uncloned, cached, and shared by all callers.
--- a/jdk/src/share/classes/sun/reflect/LangReflectAccess.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/sun/reflect/LangReflectAccess.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 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);
--- a/jdk/src/share/classes/sun/reflect/ReflectionFactory.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/sun/reflect/ReflectionFactory.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Tue Jan 29 10:32:49 2013 +0100
@@ -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;
+ }
+ }
+}
--- a/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotationParser.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
* available at runtime
*/
@SuppressWarnings("unchecked")
- private static Annotation parseAnnotation(ByteBuffer buf,
+ static Annotation parseAnnotation(ByteBuffer buf,
ConstantPool constPool,
Class<?> container,
boolean exceptionOnMissingAnnotationClass) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Tue Jan 29 10:32:49 2013 +0100
@@ -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);
+ }
+}
--- a/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
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;
+ }
}
--- a/jdk/src/share/javavm/export/jvm.h Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/javavm/export/jvm.h Tue Jan 29 10:32:49 2013 +0100
@@ -465,6 +465,12 @@
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
*/
--- a/jdk/src/share/native/java/lang/Class.c Sat Jan 26 16:57:02 2013 +0000
+++ b/jdk/src/share/native/java/lang/Class.c Tue Jan 29 10:32:49 2013 +0100
@@ -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 @@
{"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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/annotation/TypeAnnotationReflection.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/annotation/TypeParamAnnotation.java Tue Jan 29 10:32:49 2013 +0100
@@ -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();
+}