--- old/src/share/classes/java/lang/Class.java 2013-01-17 16:42:32.857325458 +0100 +++ new/src/share/classes/java/lang/Class.java 2013-01-17 16:42:32.629320938 +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,55 @@ * Maintained by the ClassValue class. */ transient ClassValue.ClassValueMap classValueMap; + + // AnnotatedType since 1.8 + + /** + * Returns an AnnotatedType object that represents the use of a type to denote + * the superclass of the entity represented by this Class. (The _use_ of type + * Foo to denote the superclass in '... extends Foo' is distinct from the + * _declaration_ 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 + * denote superinterfaces of the entity represented by this Class. (The _use_ + * of type Foo to denote a superinterface in '... implements Foo' is + * distinct from the _declaration_ of type Foo.) + * + * If this Class represents a class, the return value is an array + * containing objects representing the uses of interface types to denote + * 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 denote + * 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); + } } --- old/src/share/classes/java/lang/System.java 2013-01-17 16:42:33.461337431 +0100 +++ new/src/share/classes/java/lang/System.java 2013-01-17 16:42:33.229332832 +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 getDirectDeclaredAnnotation(Class klass, Class anno) { return klass.getDirectDeclaredAnnotation(anno); } + public byte[] getRawClassTypeAnnotations(Class klass) { + return klass.getRawTypeAnnotations(); + } + public byte[] getRawExecutableTypeAnnotations(Executable executable) { + return Class.getExecutableTypeAnnotationBytes(executable); + } public > E[] getEnumConstantsShared(Class klass) { return klass.getEnumConstantsShared(); --- old/src/share/classes/java/lang/reflect/Constructor.java 2013-01-17 16:42:34.025348611 +0100 +++ new/src/share/classes/java/lang/reflect/Constructor.java 2013-01-17 16:42:33.801344170 +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 @@ -27,6 +27,7 @@ import sun.reflect.ConstructorAccessor; import sun.reflect.Reflection; +import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; @@ -154,6 +155,10 @@ byte[] getAnnotationBytes() { return annotations; } + @Override + byte[] getTypeAnnotationBytes() { + return typeAnnotations; + } /** * {@inheritDoc} @@ -518,4 +523,8 @@ } } } + + public AnnotatedType getAnnotatedReturnType() { + return getAnnotatedReturnType0(getDeclaringClass()); +} } --- old/src/share/classes/java/lang/reflect/Executable.java 2013-01-17 16:42:34.581359632 +0100 +++ new/src/share/classes/java/lang/reflect/Executable.java 2013-01-17 16:42:34.353355113 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 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. @@ -403,4 +406,76 @@ } return declaredAnnotations; } + + // AnnotatedType since 1.8 + /* Helper for subclasses of Executable. + * + * Returns an AnnotatedType object that represents the use of a type to denote + * the return type of the method/constructor represented by this + * Executable. + */ + AnnotatedType getAnnotatedReturnType0(Type returnType) { + return TypeAnnotationParser.buildAnnotatedType0(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 denote + * (via a 'this' parameter) the implicit receiver type of the + * method/constructor represented by this Executable. + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedReceiverType() { + return TypeAnnotationParser.buildAnnotatedType0(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 denote 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() { + return null; + } + + /** + * Returns an array of AnnotatedType objects that represent the use of + * types to denote 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.buildAnnotatedTypes0(getTypeAnnotationBytes(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericExceptionTypes(), + TypeAnnotation.TypeAnnotationTarget.THROWS); + } } --- old/src/share/classes/java/lang/reflect/Field.java 2013-01-17 16:42:35.141370733 +0100 +++ new/src/share/classes/java/lang/reflect/Field.java 2013-01-17 16:42:34.909366134 +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 denote + * the declared type of the field represented by this Field. + * + * @since 1.8 + */ + public AnnotatedType getAnnotatedType() { + return TypeAnnotationParser.buildAnnotatedType0(typeAnnotations, + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericType(), + TypeAnnotation.TypeAnnotationTarget.FIELD_TYPE); +} } --- old/src/share/classes/java/lang/reflect/Method.java 2013-01-17 16:42:35.705381913 +0100 +++ new/src/share/classes/java/lang/reflect/Method.java 2013-01-17 16:42:35.477377393 +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 @@ -165,6 +165,10 @@ byte[] getAnnotationBytes() { return annotations; } + @Override + byte[] getTypeAnnotationBytes() { + return typeAnnotations; + } /** * {@inheritDoc} @@ -619,4 +623,8 @@ void handleParameterNumberMismatch(int resultLength, int numParameters) { throw new AnnotationFormatError("Parameter annotations don't match number of parameters"); } + + public AnnotatedType getAnnotatedReturnType() { + return getAnnotatedReturnType0(getGenericReturnType()); +} } --- old/src/share/classes/java/lang/reflect/ReflectAccess.java 2013-01-17 16:42:36.261392935 +0100 +++ new/src/share/classes/java/lang/reflect/ReflectAccess.java 2013-01-17 16:42:36.037388494 +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 --- old/src/share/classes/java/lang/reflect/TypeVariable.java 2013-01-17 16:42:36.837404353 +0100 +++ new/src/share/classes/java/lang/reflect/TypeVariable.java 2013-01-17 16:42:36.613399912 +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(); } --- old/src/share/classes/sun/misc/JavaLangAccess.java 2013-01-17 16:42:37.393415374 +0100 +++ new/src/share/classes/sun/misc/JavaLangAccess.java 2013-01-17 16:42:37.161410775 +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. --- old/src/share/classes/sun/reflect/LangReflectAccess.java 2013-01-17 16:42:37.941426237 +0100 +++ new/src/share/classes/sun/reflect/LangReflectAccess.java 2013-01-17 16:42:37.705421559 +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); @@ -93,7 +96,6 @@ /** Gets the "parameterAnnotations" field from a Constructor (used for serialization) */ public byte[] getConstructorParameterAnnotations(Constructor c); - // // Copying routines, needed to quickly fabricate new Field, // Method, and Constructor objects from templates // --- old/src/share/classes/sun/reflect/ReflectionFactory.java 2013-01-17 16:42:38.489437100 +0100 +++ new/src/share/classes/sun/reflect/ReflectionFactory.java 2013-01-17 16:42:38.257432501 +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 --- old/src/share/classes/sun/reflect/annotation/AnnotationParser.java 2013-01-17 16:42:39.041448042 +0100 +++ new/src/share/classes/sun/reflect/annotation/AnnotationParser.java 2013-01-17 16:42:38.809443443 +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) { --- old/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java 2013-01-17 16:42:39.601459143 +0100 +++ new/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java 2013-01-17 16:42:39.373454623 +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; @@ -188,39 +193,69 @@ return false; } + @SuppressWarnings("unchecked") public T getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - return null; + return (T)mapAnnotations(getAnnotations()).get(annotationClass); } public T getDeclaredAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - return null; + return getAnnotation(annotationClass); } @SuppressWarnings("unchecked") public T[] getAnnotations(Class 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[] getDeclaredAnnotations(Class 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) + return EMPTY_ANNOTATION_ARRAY; // This should not happen + return TypeAnnotationParser.parseTypeParameterAnnotations(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]; + + 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, Annotation> mapAnnotations(Annotation[] annos) { + Map, Annotation> result = + new LinkedHashMap, Annotation>(); + for (Annotation a : annos) { + Class 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; + } } --- old/src/share/javavm/export/jvm.h 2013-01-17 16:42:40.161470244 +0100 +++ new/src/share/javavm/export/jvm.h 2013-01-17 16:42:39.925465565 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -468,6 +468,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 */ --- old/src/share/native/java/lang/Class.c 2013-01-17 16:42:40.729481503 +0100 +++ new/src/share/native/java/lang/Class.c 2013-01-17 16:42:40.497476904 +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 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/java/lang/reflect/AnnotatedArrayType.java 2013-01-17 16:42:41.041487688 +0100 @@ -0,0 +1,35 @@ +/* + * 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. + */ +public interface AnnotatedArrayType extends AnnotatedType { + AnnotatedType getAnnotatedGenericComponentType(); +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/java/lang/reflect/AnnotatedParameterizedType.java 2013-01-17 16:42:41.585498471 +0100 @@ -0,0 +1,34 @@ +/* + * 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. + */ +public interface AnnotatedParameterizedType extends AnnotatedType { + AnnotatedType[] getAnnotatedActualTypeArguments(); +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/java/lang/reflect/AnnotatedType.java 2013-01-17 16:42:42.105508779 +0100 @@ -0,0 +1,34 @@ +/* + * 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. + */ +public interface AnnotatedType extends AnnotatedElement {} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/java/lang/reflect/AnnotatedTypeVariable.java 2013-01-17 16:42:42.629519166 +0100 @@ -0,0 +1,35 @@ +/* + * 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. + */ +public interface AnnotatedTypeVariable extends AnnotatedType { + AnnotatedType[] getAnnotatedBounds(); +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/java/lang/reflect/AnnotatedWildcardType.java 2013-01-17 16:42:43.149529474 +0100 @@ -0,0 +1,35 @@ +/* + * 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. + */ +public interface AnnotatedWildcardType extends AnnotatedType { + AnnotatedType[] getAnnotatedLowerBounds(); + AnnotatedType[] getAnnotatedUpperBounds(); +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java 2013-01-17 16:42:43.673539862 +0100 @@ -0,0 +1,280 @@ +/* + * 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 { + 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); + } + // Assert here? because this should not be happening + return EMPTY_ANNOTATED_TYPE; + } + + 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 Type type; + private AnnotatedElement decl; + private LocationInfo location; + private TypeAnnotation[] allOnSameTargetTypeAnnotations; + private Map, 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.mapAnnotations(location.filter(actualTypeAnnotations)); + } + public final boolean isAnnotationPresent(Class annotation) { + return annotations.get(annotation) != null; + } + public final Annotation[] getAnnotations() { + return getDeclaredAnnotations(); + } + public final T getAnnotation(Class annotation) { + return getDeclaredAnnotation(annotation); + } + public final T[] getAnnotations(Class annotation) { + return getDeclaredAnnotations(annotation); + } + public Annotation[] getDeclaredAnnotations() { + return annotations.values().toArray(new Annotation[0]); + } + @SuppressWarnings("unchecked") + public T getDeclaredAnnotation(Class annotation) { + return (T)annotations.get(annotation); + } + public T[] getDeclaredAnnotations(Class annotation) { + return AnnotationSupport.getMultipleAnnotations(annotations, annotation); + } + + Type getType() { + return type; + } + 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); + } + 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); + } + + private TypeVariable getTypeVariable() { + return (TypeVariable)getType(); + } + public AnnotatedType[] getAnnotatedBounds() { + return getTypeVariable().getAnnotatedBounds(); + } + } + + 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); + } + public AnnotatedType[] getAnnotatedActualTypeArguments() { + Type[] arguments = getParameterizedType().getActualTypeArguments(); + AnnotatedType[] res = new AnnotatedType[arguments.length]; + Arrays.fill(res, EMPTY_ANNOTATED_TYPE); + for (int i = 0; i < res.length; i++) { + List l = new ArrayList<>(); + 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 boolean hasUpperBounds; + AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location, + TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations, + AnnotatedElement decl) { + super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl); + hasUpperBounds = (type.getLowerBounds().length == 0); + } + + public AnnotatedType[] getAnnotatedUpperBounds() { + if (!hasUpperBounds()) + return new AnnotatedType[0]; + return getAnnotatedBounds(getWildcardType().getUpperBounds()); + } + + 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(); + for (int i = 0; i < res.length; i++) { + List l = new ArrayList<>(); + 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; + } + } +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/sun/reflect/annotation/TypeAnnotation.java 2013-01-17 16:42:44.197550249 +0100 @@ -0,0 +1,216 @@ +/* + * 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; + +public class TypeAnnotation { + private TypeAnnotationTargetInfo targetInfo; + private LocationInfo loc; + private Annotation annotation; + private AnnotatedElement baseDeclaration; + + public TypeAnnotationTargetInfo getTargetInfo() { + return targetInfo; + } + public void setTargetInfo(TypeAnnotationTargetInfo targetInfo) { + this.targetInfo = targetInfo; + } + public Annotation getAnnotation() { + return annotation; + } + public void setAnnotation(Annotation annotation) { + this.annotation = annotation; + } + public AnnotatedElement getBaseDeclaration() { + return baseDeclaration; + } + public void setBaseDeclaration(AnnotatedElement a) { + this.baseDeclaration = a; + } + public LocationInfo getLocationInfo() { + return loc; + } + public void setLocationInfo(LocationInfo a) { + this.loc = a; + } + + public static List filter(TypeAnnotation[] typeAnnotations, + TypeAnnotationTarget predicate) { + List typeAnnos = new ArrayList<>(); + for (TypeAnnotation t : typeAnnotations) + if (t.getTargetInfo().getTarget() == predicate) + typeAnnos.add(t); + 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 TypeAnnotationTarget target; + private int count = -2; // -2 is not a valid index + private int secondIndex = -1; + + public TypeAnnotationTargetInfo(TypeAnnotationTarget target) { + this.target = target; + } + + public TypeAnnotationTarget getTarget() { + return target; + } + public void setTarget(TypeAnnotationTarget target) { + this.target = target; + } + public int getCount() { + return count; + } + public void setCount(int count) { + this.count = count; + } + public int getSecondIndex() { + return secondIndex; + } + public void setSecondIndex(int i) { + this.secondIndex = i; + } + + @Override + public String toString() { + return "" + target + ": " + count + ", " + secondIndex; + } + } + + 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(); + locations[i].tag = tag; + locations[i].index = 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) { + List 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 byte tag; + public 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; + } + public Location() { + this((byte)0,(byte)0); + } + } + } + + public String toString() { + return annotation.toString() + " with Targetnfo: " + + targetInfo.toString() + " on base declaration: " + + baseDeclaration.toString(); + } +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java 2013-01-17 16:42:44.721560636 +0100 @@ -0,0 +1,411 @@ +/* + * 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.*; + +public class TypeAnnotationParser { + // Position codes + private static final byte CLASS_TYPE_PARAMETER_CODE = 0x00; + private static final byte METHOD_TYPE_PARAMETER_CODE = 0x02; + private static final byte CLASS_EXTENDS_CODE = 0x10; + private static final byte CLASS_TYPE_PARAMETER_BOUND_CODE = 0x12; + private static final byte METHOD_TYPE_PARAMETER_BOUND_CODE = 0x14; + private static final byte FIELD_CODE = 0x16; + private static final byte METHOD_RETURN_CODE = 0x18; + private static final byte METHOD_RECEIVER_CODE = 0x1A; + private static final byte METHOD_PARAMETER_CODE = 0x1C; + private static final byte THROWS_CODE = 0x1E; + private static final byte LOCAL_VARIABLE_CODE = (byte)0x80; + private static final byte RESOURCE_VARIABLE_CODE = (byte)0x82; + private static final byte EXCEPTION_PARAMETER_CODE = (byte)0x84; + private static final byte CAST_CODE = (byte)0x86; + private static final byte INSTANCEOF_CODE = (byte)0x88; + private static final byte NEW_CODE = (byte)0x8A; + private static final byte CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT_CODE = (byte)0x8C; + private static final byte METHOD_INVOCATION_TYPE_ARGUMENT_CODE = (byte)0x8E; + private static final byte LAMBDA_FORMAL_PARAMETER_CODE = (byte)0x90; + private static final byte METHOD_REFERENCE_TYPE_ARGUMENT_CODE = (byte)0x92; + + /** + * Parse type annotations encoded as an array of bytes. + */ + public 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 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); + } + + /** + * Parse all type annotations on the declaration supplied. + */ + public 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); + } + + + 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; + TypeAnnotation ta = new TypeAnnotation(); + ta.setAnnotation(a); + ta.setTargetInfo(ti); + ta.setBaseDeclaration(baseDecl); + ta.setLocationInfo(locationInfo); + return ta; + } + + private static TypeAnnotationTargetInfo parseTargetInfo(ByteBuffer buf) { + byte posCode = buf.get(); + switch(posCode) { + case CAST_CODE: + case INSTANCEOF_CODE: + case NEW_CODE: { + short offset = buf.getShort(); + // CONSTRUCTORS HERE + } break; + case LOCAL_VARIABLE_CODE: + case RESOURCE_VARIABLE_CODE: + short length = buf.getShort(); + // probably create an array + for (int i = 0; i < length; ++i) { + short offset = buf.getShort(); + short varLength = buf.getShort(); + short index = buf.getShort(); + // probably add entries to an array + } + // CONSTRUCTORS HERE + break; + case EXCEPTION_PARAMETER_CODE: { + byte index = buf.get(); + // CONSTRUCTORS HERE + } break; + case METHOD_RECEIVER_CODE: + // no additional payload + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER_TYPE); + case CLASS_TYPE_PARAMETER_CODE: + case METHOD_TYPE_PARAMETER_CODE: { + byte index = buf.get(); + TypeAnnotationTargetInfo res; + if (posCode == CLASS_TYPE_PARAMETER_CODE) + res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_TYPE_PARAMETER); + else + res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_TYPE_PARAMETER); + res.setCount(index); + return res; + } + case CLASS_TYPE_PARAMETER_BOUND_CODE: + case METHOD_TYPE_PARAMETER_BOUND_CODE: { + byte parameter_index = buf.get(); + byte bound_index = buf.get(); + TypeAnnotationTargetInfo res; + if (posCode == CLASS_TYPE_PARAMETER_BOUND_CODE) + res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_PARAMETER_BOUND); + else + res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_PARAMETER_BOUND); + res.setCount(parameter_index); + res.setSecondIndex(bound_index); + return res; + } + case CLASS_EXTENDS_CODE: { + short index = buf.getShort(); + // CONSTRUCTORS HERE + if (index == -1) { + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_EXTENDS); + } else if (index >= 0) { + TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_IMPLEMENTS); + res.setCount(index); + return res; + } + } break; + case THROWS_CODE: { + short index = buf.getShort(); + TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.THROWS); + res.setCount(index); + return res; + } + case METHOD_PARAMETER_CODE: { + byte index = buf.get(); + // CONSTRUCTORS HERE + } break; + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT_CODE: + case METHOD_INVOCATION_TYPE_ARGUMENT_CODE: + case METHOD_REFERENCE_TYPE_ARGUMENT_CODE: { + short offset = buf.getShort(); + byte index = buf.get(); + } break; + case METHOD_RETURN_CODE: + // no additional payload + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN_TYPE); + //break; /*unreachable*/ + case FIELD_CODE: + // no additional payload + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD_TYPE); + //break; /*unreachable*/ + case LAMBDA_FORMAL_PARAMETER_CODE: { + byte index = buf.get(); + // CONSTRUCTORS HERE + } break; + default: + // probably throw some exception + break; + } + return null; + } + + // Helper + @SuppressWarnings({"rawtypes", "unchecked"}) + public static AnnotatedType[] buildAnnotatedTypes0(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); + ArrayList[] l = new ArrayList[size]; // array of ArrayList + + 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) { + l[pos] = new ArrayList(); + } + l[pos].add(t); + } + } + for (int i = 0; i < size; i++) { + ArrayList 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; + } + public static AnnotatedType buildAnnotatedType0(byte[] rawAnnotations, + ConstantPool cp, + AnnotatedElement decl, + Class container, + Type type, + TypeAnnotationTarget filter) { + TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations, + cp, + decl, + container); + List l = new ArrayList<>(); + 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); + } + + // Class + public static AnnotatedType buildAnnotatedSuperclass(byte[] rawAnnotations, + ConstantPool cp, + Class decl) { + Type supertype = decl.getGenericSuperclass(); + if (supertype == null) + return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE; + return buildAnnotatedType0(rawAnnotations, + cp, + decl, + decl, + supertype, + TypeAnnotationTarget.CLASS_EXTENDS); + } + public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations, + ConstantPool cp, + Class decl) { + return buildAnnotatedTypes0(rawAnnotations, + cp, + decl, + decl, + decl.getGenericInterfaces(), + TypeAnnotationTarget.CLASS_IMPLEMENTS); + } + + // TypeVariable + public static Annotation[] parseTypeParameterAnnotations(D genericsDecl, + int typeParameterIndex) { + AnnotatedElement decl; + TypeAnnotationTarget predicate; + if (genericsDecl instanceof Class) { + decl = (Class)genericsDecl; + predicate = TypeAnnotationTarget.CLASS_TYPE_PARAMETER; + } else { + decl = (Executable)genericsDecl; + predicate = TypeAnnotationTarget.METHOD_TYPE_PARAMETER; + } + List typeVarAnnos = TypeAnnotation.filter(parseAllTypeAnnotations(decl), + predicate); + List res = new ArrayList<>(); + for (TypeAnnotation t : typeVarAnnos) + if (t.getTargetInfo().getCount() == typeParameterIndex) + res.add(t.getAnnotation()); + return res.toArray(new Annotation[0]); + } + + public static AnnotatedType[] parseAnnotatedBounds(Type[] bounds, + D decl, + int typeVarIndex) { + return parseAnnotatedBounds(bounds, decl, typeVarIndex, LocationInfo.BASE_LOCATION); + } + static AnnotatedType[] parseAnnotatedBounds(Type[] bounds, + D decl, + int typeVarIndex, + LocationInfo loc) { + List 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 + if (bounds.length > 0) { + Type b0 = bounds[0]; + if (!(b0 instanceof Class)) { + startIndex = 1; + } else { + Class c = (Class)b0; + if (c.isInterface()) { + // enum? anno? + startIndex = 1; + } + } + } + for (int i = 0; i < bounds.length; i++) { + List l = new ArrayList<>(); + for (TypeAnnotation t : candidates) { + TypeAnnotationTargetInfo tInfo = t.getTargetInfo(); + if (tInfo.getSecondIndex() == 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 List 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); + } + + private static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0]; + + static Map, Annotation> mapAnnotations(TypeAnnotation[] typeAnnos) { + Map, Annotation> result = + new LinkedHashMap, Annotation>(); + for (TypeAnnotation t : typeAnnos) { + Annotation a = t.getAnnotation(); + Class 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; + } +} --- /dev/null 2013-01-17 09:11:42.581489353 +0100 +++ new/test/java/lang/annotation/TypeAnnotationReflection.java 2013-01-17 16:42:45.249571102 +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 List 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.ParameterizedInner 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 { + class ParameterizedInner {} +} + +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 { + @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 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 2013-01-17 09:11:42.581489353 +0100 +++ new/test/java/lang/annotation/TypeParamAnnotation.java 2013-01-17 16:42:45.777581569 +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(); +}