8007073: Implement Core Reflection for Type Annotations on parameters
authorjfranck
Fri, 10 May 2013 10:20:13 +0200
changeset 17450 0f704861915e
parent 17449 93b0810b4d73
child 17451 7ee55c117088
8007073: Implement Core Reflection for Type Annotations on parameters Reviewed-by: darcy, abuckley
jdk/src/share/classes/java/lang/reflect/Executable.java
jdk/src/share/classes/java/lang/reflect/Field.java
jdk/src/share/classes/java/lang/reflect/Parameter.java
jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java
jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java
jdk/test/java/lang/annotation/TypeAnnotationReflection.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);
     }
 
 }
--- 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);
 }
 }
--- 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;
 
     /**
--- 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 {
--- 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
--- 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 {