# HG changeset patch # User jfranck # Date 1368174013 -7200 # Node ID 0f704861915e0c40f0ab235fc9da56d24915d7e5 # Parent 93b0810b4d731202033bb2e845a5f12a15ca7d34 8007073: Implement Core Reflection for Type Annotations on parameters Reviewed-by: darcy, abuckley diff -r 93b0810b4d73 -r 0f704861915e jdk/src/share/classes/java/lang/reflect/Executable.java --- a/jdk/src/share/classes/java/lang/reflect/Executable.java Thu May 09 14:23:49 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java Fri May 10 10:20:13 2013 +0200 @@ -510,12 +510,12 @@ */ AnnotatedType getAnnotatedReturnType0(Type returnType) { return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(), - sun.misc.SharedSecrets.getJavaLangAccess(). - getConstantPool(getDeclaringClass()), - this, - getDeclaringClass(), - returnType, - TypeAnnotation.TypeAnnotationTarget.METHOD_RETURN_TYPE); + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + returnType, + TypeAnnotation.TypeAnnotationTarget.METHOD_RETURN); } /** @@ -535,12 +535,12 @@ */ public AnnotatedType getAnnotatedReceiverType() { return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(), - sun.misc.SharedSecrets.getJavaLangAccess(). - getConstantPool(getDeclaringClass()), - this, - getDeclaringClass(), - getDeclaringClass(), - TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER_TYPE); + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getDeclaringClass(), + TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER); } /** @@ -556,7 +556,13 @@ * @since 1.8 */ public AnnotatedType[] getAnnotatedParameterTypes() { - throw new UnsupportedOperationException("Not yet"); + return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getParameterTypes(), + TypeAnnotation.TypeAnnotationTarget.METHOD_FORMAL_PARAMETER); } /** @@ -573,12 +579,12 @@ */ public AnnotatedType[] getAnnotatedExceptionTypes() { return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(), - sun.misc.SharedSecrets.getJavaLangAccess(). - getConstantPool(getDeclaringClass()), - this, - getDeclaringClass(), - getGenericExceptionTypes(), - TypeAnnotation.TypeAnnotationTarget.THROWS); + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getGenericExceptionTypes(), + TypeAnnotation.TypeAnnotationTarget.THROWS); } } diff -r 93b0810b4d73 -r 0f704861915e jdk/src/share/classes/java/lang/reflect/Field.java --- a/jdk/src/share/classes/java/lang/reflect/Field.java Thu May 09 14:23:49 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Field.java Fri May 10 10:20:13 2013 +0200 @@ -1161,6 +1161,6 @@ this, getDeclaringClass(), getGenericType(), - TypeAnnotation.TypeAnnotationTarget.FIELD_TYPE); + TypeAnnotation.TypeAnnotationTarget.FIELD); } } diff -r 93b0810b4d73 -r 0f704861915e jdk/src/share/classes/java/lang/reflect/Parameter.java --- a/jdk/src/share/classes/java/lang/reflect/Parameter.java Thu May 09 14:23:49 2013 -0700 +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java Fri May 10 10:20:13 2013 +0200 @@ -200,6 +200,19 @@ return tmp; } + /** + * Returns an AnnotatedType object that represents the use of a type to + * specify the type of the formal parameter represented by this Parameter. + * + * @return an {@code AnnotatedType} object representing the use of a type + * to specify the type of the formal parameter represented by this + * Parameter + */ + public AnnotatedType getAnnotatedType() { + // no caching for now + return executable.getAnnotatedParameterTypes()[index]; + } + private transient volatile Class parameterClassCache = null; /** diff -r 93b0810b4d73 -r 0f704861915e jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java --- a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java Thu May 09 14:23:49 2013 -0700 +++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java Fri May 10 10:20:13 2013 +0200 @@ -83,12 +83,13 @@ CLASS_TYPE_PARAMETER, METHOD_TYPE_PARAMETER, CLASS_EXTENDS, - CLASS_IMPLEMENTS, - CLASS_PARAMETER_BOUND, - METHOD_PARAMETER_BOUND, - METHOD_RETURN_TYPE, - METHOD_RECEIVER_TYPE, - FIELD_TYPE, + CLASS_IMPLEMENTS, // Not in the spec + CLASS_TYPE_PARAMETER_BOUND, + METHOD_TYPE_PARAMETER_BOUND, + FIELD, + METHOD_RETURN, + METHOD_RECEIVER, + METHOD_FORMAL_PARAMETER, THROWS; } public static class TypeAnnotationTargetInfo { diff -r 93b0810b4d73 -r 0f704861915e jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java --- a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Thu May 09 14:23:49 2013 -0700 +++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Fri May 10 10:20:13 2013 +0200 @@ -282,10 +282,10 @@ AnnotatedElement boundsDecl; TypeAnnotationTarget target; if (decl instanceof Class) { - target = TypeAnnotationTarget.CLASS_PARAMETER_BOUND; + target = TypeAnnotationTarget.CLASS_TYPE_PARAMETER_BOUND; boundsDecl = (Class)decl; } else { - target = TypeAnnotationTarget.METHOD_PARAMETER_BOUND; + target = TypeAnnotationTarget.METHOD_TYPE_PARAMETER_BOUND; boundsDecl = (Executable)decl; } return TypeAnnotation.filter(TypeAnnotationParser.parseAllTypeAnnotations(boundsDecl), target); @@ -371,14 +371,15 @@ 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 final byte INSTANCEOF = (byte)0x43; + private static final byte NEW = (byte)0x44; + private static final byte CONSTRUCTOR_REFERENCE = (byte)0x45; + private static final byte METHOD_REFERENCE = (byte)0x46; + private static final byte CAST = (byte)0x47; + private static final byte CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = (byte)0x48; + private static final byte METHOD_INVOCATION_TYPE_ARGUMENT = (byte)0x49; + private static final byte CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = (byte)0x4A; + private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x4B; private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf, ConstantPool cp, @@ -417,19 +418,20 @@ return res; }} break; case CLASS_TYPE_PARAMETER_BOUND: - return parse2ByteTarget(TypeAnnotationTarget.CLASS_PARAMETER_BOUND, buf); + return parse2ByteTarget(TypeAnnotationTarget.CLASS_TYPE_PARAMETER_BOUND, buf); case METHOD_TYPE_PARAMETER_BOUND: - return parse2ByteTarget(TypeAnnotationTarget.METHOD_PARAMETER_BOUND, buf); + return parse2ByteTarget(TypeAnnotationTarget.METHOD_TYPE_PARAMETER_BOUND, buf); case FIELD: - return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD_TYPE); + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD); case METHOD_RETURN: - return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN_TYPE); + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN); case METHOD_RECEIVER: - return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER_TYPE); + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER); case METHOD_FORMAL_PARAMETER: { - // Todo byte index = buf.get(); - } break; + return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_FORMAL_PARAMETER, + index); + } //unreachable break; case THROWS: return parseShortTarget(TypeAnnotationTarget.THROWS, buf); @@ -445,30 +447,27 @@ short varLength = buf.getShort(); short index = buf.getShort(); } - break; + return null; case EXCEPTION_PARAMETER: { byte index = buf.get(); - } break; - case CAST: + } + return null; case INSTANCEOF: - case NEW: { - short offset = buf.getShort(); - } break; - case CONSTRUCTOR_REFERENCE_RECEIVER: - case METHOD_REFERENCE_RECEIVER: { + case NEW: + case CONSTRUCTOR_REFERENCE: + case METHOD_REFERENCE: { 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; + } + return null; + case CAST: + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT: { short offset = buf.getShort(); byte index = buf.get(); - } break; + } + return null; default: // will throw error below diff -r 93b0810b4d73 -r 0f704861915e jdk/test/java/lang/annotation/TypeAnnotationReflection.java --- a/jdk/test/java/lang/annotation/TypeAnnotationReflection.java Thu May 09 14:23:49 2013 -0700 +++ b/jdk/test/java/lang/annotation/TypeAnnotationReflection.java Fri May 10 10:20:13 2013 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 8004698 + * @bug 8004698 8007073 * @summary Unit test for type annotations */ @@ -48,6 +48,8 @@ testParameterizedType(); testNestedParameterizedType(); testWildcardType(); + testParameterTypes(); + testParameterType(); } private static void check(boolean b) { @@ -359,6 +361,154 @@ t = w.getAnnotatedLowerBounds(); check(t.length == 1); } + + private static void testParameterTypes() throws Exception { + // NO PARAMS + Method m = Params.class.getDeclaredMethod("noParams", (Class[])null); + AnnotatedType[] t = m.getAnnotatedParameterTypes(); + check(t.length == 0); + + // ONLY ANNOTATED PARAM TYPES + Class[] argsArr = {String.class, String.class, String.class}; + m = Params.class.getDeclaredMethod("onlyAnnotated", (Class[])argsArr); + t = m.getAnnotatedParameterTypes(); + check(t.length == 3); + + check(t[0].getAnnotations().length == 1); + check(t[0].getAnnotation(TypeAnno.class) != null); + check(t[0].getAnnotationsByType(TypeAnno.class)[0].value().equals("1")); + + check(t[1].getAnnotations().length == 1); + check(t[1].getAnnotation(TypeAnno.class) != null); + check(t[1].getAnnotationsByType(TypeAnno.class)[0].value().equals("2")); + + check(t[2].getAnnotations().length == 2); + check(t[2].getAnnotations()[0].annotationType().equals(TypeAnno.class)); + check(t[2].getAnnotation(TypeAnno.class) != null); + check(t[2].getAnnotation(TypeAnno2.class) != null); + check(t[2].getAnnotationsByType(TypeAnno.class)[0].value().equals("3a")); + check(t[2].getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b")); + + // MIXED ANNOTATED PARAM TYPES + m = Params.class.getDeclaredMethod("mixed", (Class[])argsArr); + t = m.getAnnotatedParameterTypes(); + check(t.length == 3); + + check(t[0].getAnnotations().length == 1); + check(t[0].getAnnotation(TypeAnno.class) != null); + check(t[0].getAnnotationsByType(TypeAnno.class)[0].value().equals("1")); + + check(t[1].getAnnotations().length == 0); + check(t[1].getAnnotation(TypeAnno.class) == null); + check(t[1].getAnnotation(TypeAnno2.class) == null); + + check(t[2].getAnnotations().length == 2); + check(t[2].getAnnotations()[0].annotationType().equals(TypeAnno.class)); + check(t[2].getAnnotation(TypeAnno.class) != null); + check(t[2].getAnnotation(TypeAnno2.class) != null); + check(t[2].getAnnotationsByType(TypeAnno.class)[0].value().equals("3a")); + check(t[2].getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b")); + + // NO ANNOTATED PARAM TYPES + m = Params.class.getDeclaredMethod("unAnnotated", (Class[])argsArr); + t = m.getAnnotatedParameterTypes(); + check(t.length == 3); + + check(t[0].getAnnotations().length == 0); + check(t[0].getAnnotation(TypeAnno.class) == null); + check(t[0].getAnnotation(TypeAnno2.class) == null); + + check(t[1].getAnnotations().length == 0); + check(t[1].getAnnotation(TypeAnno.class) == null); + check(t[1].getAnnotation(TypeAnno2.class) == null); + + check(t[2].getAnnotations().length == 0); + check(t[2].getAnnotation(TypeAnno.class) == null); + check(t[2].getAnnotation(TypeAnno2.class) == null); + } + + private static void testParameterType() throws Exception { + // NO PARAMS + Method m = Params.class.getDeclaredMethod("noParams", (Class[])null); + Parameter[] p = m.getParameters(); + check(p.length == 0); + + // ONLY ANNOTATED PARAM TYPES + Class[] argsArr = {String.class, String.class, String.class}; + m = Params.class.getDeclaredMethod("onlyAnnotated", (Class[])argsArr); + p = m.getParameters(); + check(p.length == 3); + AnnotatedType t0 = p[0].getAnnotatedType(); + AnnotatedType t1 = p[1].getAnnotatedType(); + AnnotatedType t2 = p[2].getAnnotatedType(); + + check(t0.getAnnotations().length == 1); + check(t0.getAnnotation(TypeAnno.class) != null); + check(t0.getAnnotationsByType(TypeAnno.class)[0].value().equals("1")); + + check(t1.getAnnotations().length == 1); + check(t1.getAnnotation(TypeAnno.class) != null); + check(t1.getAnnotationsByType(TypeAnno.class)[0].value().equals("2")); + + check(t2.getAnnotations().length == 2); + check(t2.getAnnotations()[0].annotationType().equals(TypeAnno.class)); + check(t2.getAnnotation(TypeAnno.class) != null); + check(t2.getAnnotation(TypeAnno2.class) != null); + check(t2.getAnnotationsByType(TypeAnno.class)[0].value().equals("3a")); + check(t2.getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b")); + + // MIXED ANNOTATED PARAM TYPES + m = Params.class.getDeclaredMethod("mixed", (Class[])argsArr); + p = m.getParameters(); + check(p.length == 3); + + t0 = p[0].getAnnotatedType(); + t1 = p[1].getAnnotatedType(); + t2 = p[2].getAnnotatedType(); + + check(t0.getAnnotations().length == 1); + check(t0.getAnnotation(TypeAnno.class) != null); + check(t0.getAnnotationsByType(TypeAnno.class)[0].value().equals("1")); + + check(t1.getAnnotations().length == 0); + check(t1.getAnnotation(TypeAnno.class) == null); + check(t1.getAnnotation(TypeAnno2.class) == null); + + check(t2.getAnnotations().length == 2); + check(t2.getAnnotations()[0].annotationType().equals(TypeAnno.class)); + check(t2.getAnnotation(TypeAnno.class) != null); + check(t2.getAnnotation(TypeAnno2.class) != null); + check(t2.getAnnotationsByType(TypeAnno.class)[0].value().equals("3a")); + check(t2.getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b")); + + // NO ANNOTATED PARAM TYPES + m = Params.class.getDeclaredMethod("unAnnotated", (Class[])argsArr); + p = m.getParameters(); + check(p.length == 3); + + t0 = p[0].getAnnotatedType(); + t1 = p[1].getAnnotatedType(); + t2 = p[2].getAnnotatedType(); + + check(t0.getAnnotations().length == 0); + check(t0.getAnnotation(TypeAnno.class) == null); + check(t0.getAnnotation(TypeAnno2.class) == null); + + check(t1.getAnnotations().length == 0); + check(t1.getAnnotation(TypeAnno.class) == null); + check(t1.getAnnotation(TypeAnno2.class) == null); + + check(t2.getAnnotations().length == 0); + check(t2.getAnnotation(TypeAnno.class) == null); + check(t2.getAnnotation(TypeAnno2.class) == null); + } +} + +class Params { + public void noParams() {} + public void onlyAnnotated(@TypeAnno("1") String s1, @TypeAnno("2") String s2, @TypeAnno("3a") @TypeAnno2("3b") String s3) {} + public void mixed(@TypeAnno("1") String s1, String s2, @TypeAnno("3a") @TypeAnno2("3b") String s3) {} + public void unAnnotated(String s1, String s2, String s3) {} } abstract class TestWildcardType {