mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-20 11:50:25 +00:00
8007073: Implement Core Reflection for Type Annotations on parameters
Reviewed-by: darcy, abuckley
This commit is contained in:
parent
dfc792a1b8
commit
5d83fde0d1
@ -510,12 +510,12 @@ public abstract class Executable extends AccessibleObject
|
||||
*/
|
||||
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 abstract class Executable extends AccessibleObject
|
||||
*/
|
||||
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 @@ public abstract class Executable extends AccessibleObject
|
||||
* @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 abstract class Executable extends AccessibleObject
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1161,6 +1161,6 @@ class Field extends AccessibleObject implements Member {
|
||||
this,
|
||||
getDeclaringClass(),
|
||||
getGenericType(),
|
||||
TypeAnnotation.TypeAnnotationTarget.FIELD_TYPE);
|
||||
TypeAnnotation.TypeAnnotationTarget.FIELD);
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,6 +200,19 @@ public final class Parameter implements AnnotatedElement {
|
||||
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;
|
||||
|
||||
/**
|
||||
|
||||
@ -83,12 +83,13 @@ public class TypeAnnotation {
|
||||
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 {
|
||||
|
||||
@ -282,10 +282,10 @@ public class TypeAnnotationParser {
|
||||
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 @@ public class TypeAnnotationParser {
|
||||
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 @@ public class TypeAnnotationParser {
|
||||
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 @@ public class TypeAnnotationParser {
|
||||
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: {
|
||||
case NEW:
|
||||
case CONSTRUCTOR_REFERENCE:
|
||||
case METHOD_REFERENCE: {
|
||||
short offset = buf.getShort();
|
||||
} break;
|
||||
case CONSTRUCTOR_REFERENCE_RECEIVER:
|
||||
case METHOD_REFERENCE_RECEIVER: {
|
||||
short offset = buf.getShort();
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
case LAMBDA_FORMAL_PARAMETER: {
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
case METHOD_REFERENCE:
|
||||
// This one isn't in the spec yet
|
||||
break;
|
||||
}
|
||||
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
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8004698
|
||||
* @bug 8004698 8007073
|
||||
* @summary Unit test for type annotations
|
||||
*/
|
||||
|
||||
@ -48,6 +48,8 @@ public class TypeAnnotationReflection {
|
||||
testParameterizedType();
|
||||
testNestedParameterizedType();
|
||||
testWildcardType();
|
||||
testParameterTypes();
|
||||
testParameterType();
|
||||
}
|
||||
|
||||
private static void check(boolean b) {
|
||||
@ -359,6 +361,154 @@ public class TypeAnnotationReflection {
|
||||
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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user