8007073: Implement Core Reflection for Type Annotations on parameters
Reviewed-by: darcy, abuckley
--- 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 {