Merge "Synthetic constructor parameter annotation tests" into pi-dev
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
index cb49aef..3c22aa8 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
@@ -23,6 +23,7 @@
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
@@ -154,7 +155,7 @@
}
// Tests for isAnnotationPresent and getDeclaredAnnotation.
- public void testMethodDeclaredAnnotation() throws Exception {
+ public void testMethodDeclaredAnnotation_repeated() throws Exception {
Class<? extends Annotation> repeated = Repeated.class;
checkParameter0DeclaredAnnotation(
AnnotatedMethodClass.getMethodWithoutAnnotations(),
@@ -231,7 +232,7 @@
}
// Tests for isAnnotationPresent and getDeclaredAnnotation.
- public void testConstructorDeclaredAnnotation() throws Exception {
+ public void testConstructorDeclaredAnnotation_repeated() throws Exception {
Class<? extends Annotation> repeated = Repeated.class;
checkParameter0DeclaredAnnotation(
AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
@@ -279,7 +280,7 @@
assertGetDeclaredAnnotation(parameter, annotationType, expectedAnnotationString);
}
- public void testMethodGetDeclaredAnnotationsByType() throws Exception {
+ public void testMethodGetDeclaredAnnotationsByType_repeated() throws Exception {
Class<? extends Annotation> repeated = Repeated.class;
checkParameter0GetDeclaredAnnotationsByType(
AnnotatedMethodClass.getMethodWithoutAnnotations(),
@@ -315,7 +316,7 @@
container, EXPECT_EMPTY);
}
- public void testConstructorGetDeclaredAnnotationsByType() throws Exception {
+ public void testConstructorGetDeclaredAnnotationsByType_repeated() throws Exception {
Class<? extends Annotation> repeated = Repeated.class;
checkParameter0GetDeclaredAnnotationsByType(
AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
@@ -359,7 +360,7 @@
parameter, annotationType, expectedAnnotationStrings);
}
- public void testMethodGetAnnotationsByType() throws Exception {
+ public void testMethodGetAnnotationsByType_repeated() throws Exception {
Class<? extends Annotation> repeated = Repeated.class;
checkParameter0GetAnnotationsByType(
AnnotatedMethodClass.getMethodWithoutAnnotations(),
@@ -395,7 +396,7 @@
container, EXPECT_EMPTY);
}
- public void testConstructorGetAnnotationsByType() throws Exception {
+ public void testConstructorGetAnnotationsByType_repeated() throws Exception {
Class<? extends Annotation> repeated = Repeated.class;
checkParameter0GetAnnotationsByType(
AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
@@ -444,35 +445,104 @@
* the enclosing object, is inserted by the compiler.
*/
class InnerClass {
- InnerClass(@Repeated(1) String p1) {}
+ InnerClass(@AnnotationA String p1) {}
}
- /** Special case testing for a compiler-generated constructor parameter. */
- public void testImplicitConstructorParameters_singleAnnotation() throws Exception {
+ /** Special case testing for a compiler-generated constructor parameter. JLS 8.8.1, JLS 13.1. */
+ public void testImplicitConstructorParameters_innerClass() throws Exception {
Constructor<InnerClass> constructor =
InnerClass.class.getDeclaredConstructor(
AnnotatedElementParameterTest.class, String.class);
Parameter[] parameters = constructor.getParameters();
+ // The parameter annotation code behaves as if there are two parameters.
+
// The compiler-generated constructor should have no annotations.
Parameter parameter0 = parameters[0];
AnnotatedElementTestSupport.assertGetAnnotationsByType(
- parameter0, Repeated.class, new String[0]);
+ parameter0, AnnotationA.class, new String[0]);
AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
- parameter0, Repeated.class, new String[0]);
+ parameter0, AnnotationA.class, new String[0]);
AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
- parameter0, Repeated.class, null);
- AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, Repeated.class, false);
+ parameter0, AnnotationA.class, null);
+ AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, AnnotationA.class, false);
// The annotation should remain on the correct parameter.
Parameter parameter1 = parameters[1];
AnnotatedElementTestSupport.assertGetAnnotationsByType(
- parameter1, Repeated.class, new String[] {"@Repeated(1)"});
+ parameter1, AnnotationA.class, new String[] {"@AnnotationA"});
AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
- parameter1, Repeated.class, new String[] {"@Repeated(1)"});
+ parameter1, AnnotationA.class, new String[] {"@AnnotationA"});
AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
- parameter1, Repeated.class, "@Repeated(1)");
+ parameter1, AnnotationA.class, "@AnnotationA");
AnnotatedElementTestSupport.assertIsAnnotationPresent(
- parameter1, Repeated.class, true);
+ parameter1, AnnotationA.class, true);
+ }
+
+ static abstract class AnonymousBaseClass {
+ public AnonymousBaseClass(@AnnotationA String p1) {}
+ }
+
+ /** Special case testing for a compiler-generated constructor parameter. JLS 13.1 */
+ public void testImplicitConstructorParameters_anonymousClass() throws Exception {
+ /*
+ * As an anonymous class the constructor will actually have two parameters: the first,
+ * referencing the enclosing object, is inserted by the compiler.
+ */
+ AnonymousBaseClass anonymousClassInstance = new AnonymousBaseClass("p1") {};
+
+ Constructor<? extends AnonymousBaseClass> constructor =
+ anonymousClassInstance.getClass().getDeclaredConstructor(
+ AnnotatedElementParameterTest.class, String.class);
+ Parameter[] parameters = constructor.getParameters();
+ assertEquals(2, parameters.length);
+
+ // The parameter annotation code behaves as if there are two parameters.
+
+ // This is the synthetic parameter.
+ Parameter parameter0 = parameters[0];
+ AnnotatedElementTestSupport.assertGetAnnotationsByType(
+ parameter0, AnnotationA.class, new String[0]);
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
+ parameter0, AnnotationA.class, new String[0]);
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
+ parameter0, AnnotationA.class, null);
+ AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, AnnotationA.class, false);
+
+ // There's no annotation since we cannot annotate the parameter on the anonymous class.
+ Parameter parameter1 = parameters[1];
+ AnnotatedElementTestSupport.assertGetAnnotationsByType(
+ parameter1, AnnotationA.class, new String[0]);
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
+ parameter1, AnnotationA.class, new String[0]);
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
+ parameter1, AnnotationA.class, null);
+ AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter1, AnnotationA.class, false);
+ }
+
+ /**
+ * A static inner / nested member class will not have synthetic parameters and should behave
+ * like a top-level class.
+ */
+ static class StaticInnerClass {
+ StaticInnerClass(@AnnotationA String p1) {}
+ }
+
+ /** Special case testing for a compiler-generated constructor parameter. */
+ public void testImplicitConstructorParameters_staticInnerClass() throws Exception {
+ Constructor<StaticInnerClass> constructor =
+ StaticInnerClass.class.getDeclaredConstructor(String.class);
+ Parameter[] parameters = constructor.getParameters();
+ assertEquals(1, parameters.length);
+
+ Parameter parameter0 = parameters[0];
+ AnnotatedElementTestSupport.assertGetAnnotationsByType(
+ parameter0, AnnotationA.class, new String[] {"@AnnotationA"});
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
+ parameter0, AnnotationA.class, new String[] {"@AnnotationA"});
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
+ parameter0, AnnotationA.class, "@AnnotationA");
+ AnnotatedElementTestSupport.assertIsAnnotationPresent(
+ parameter0, AnnotationA.class, true);
}
}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java
index b17fbff..80be3f5 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java
@@ -24,6 +24,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -291,8 +292,8 @@
}
private static String createAnnotationTestString(Annotation annotation) {
- return "@" + annotation.annotationType().getSimpleName() + createArgumentsTestString(
- annotation);
+ return "@" + annotation.annotationType().getSimpleName()
+ + createArgumentsTestString(annotation);
}
private static String createArgumentsTestString(Annotation annotation) {
@@ -309,6 +310,6 @@
String repeatedValuesString = joiner.toString();
return "(" + repeatedValuesString + ")";
}
- throw new AssertionError("Unknown annotation: " + annotation);
+ return "";
}
}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
index 38d9899..96a83c2 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
@@ -22,7 +22,9 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
@@ -36,7 +38,7 @@
/**
* Tests for {@link Executable#getParameterAnnotations()} via the {@link Constructor} and
- * {@link Method} classes. See {@link AnnotatedElementParameterTest} for testing of the
+ * {@link Method} classes. See {@link for testing of the
* {@link java.lang.reflect.AnnotatedElement} methods.
*/
public class ExecutableParameterTest extends TestCase {
@@ -50,46 +52,15 @@
public void testMethodGetParameterAnnotations() throws Exception {
Method methodWithoutAnnotatedParameters = MethodClass.class.getMethod(
"methodWithoutAnnotatedParameters", String.class, String.class);
- Annotation[][] noParameterAnnotations =
- methodWithoutAnnotatedParameters.getParameterAnnotations();
- assertEquals(2, noParameterAnnotations.length);
+ Annotation[][] noParameterAnnotations = getParameterAnnotations(
+ methodWithoutAnnotatedParameters, 2);
assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
Method methodWithAnnotatedParameters = MethodClass.class.getMethod(
"methodWithAnnotatedParameters", String.class, String.class);
- Annotation[][] parameterAnnotations =
- methodWithAnnotatedParameters.getParameterAnnotations();
- assertEquals(2, parameterAnnotations.length);
- assertEquals(set(AnnotationB.class, AnnotationD.class),
- annotationsToTypes(parameterAnnotations[0]));
- assertEquals(set(AnnotationC.class, AnnotationD.class),
- annotationsToTypes(parameterAnnotations[1]));
- }
-
- private static class ConstructorClass {
- // No annotations.
- public ConstructorClass(Integer parameter1, Integer parameter2) {}
-
- // Annotations.
- public ConstructorClass(@AnnotationB @AnnotationD String parameter1,
- @AnnotationC @AnnotationD String parameter2) {}
- }
-
- public void testConstructorGetParameterAnnotations() throws Exception {
- Constructor constructorWithoutAnnotatedParameters =
- ConstructorClass.class.getDeclaredConstructor(Integer.class, Integer.class);
- Annotation[][] noParameterAnnotations =
- constructorWithoutAnnotatedParameters.getParameterAnnotations();
- assertEquals(2, noParameterAnnotations.length);
- assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
- assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
-
- Constructor constructorWithAnnotatedParameters =
- ConstructorClass.class.getDeclaredConstructor(String.class, String.class);
- Annotation[][] parameterAnnotations =
- constructorWithAnnotatedParameters.getParameterAnnotations();
- assertEquals(2, parameterAnnotations.length);
+ Annotation[][] parameterAnnotations = getParameterAnnotations(
+ methodWithAnnotatedParameters, 2);
assertEquals(set(AnnotationB.class, AnnotationD.class),
annotationsToTypes(parameterAnnotations[0]));
assertEquals(set(AnnotationC.class, AnnotationD.class),
@@ -149,29 +120,56 @@
public void testMethodGetParameterAnnotations_repeated() throws Exception {
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodClass.getMethodWithoutAnnotations(), EXPECT_EMPTY);
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
"@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
"@Container({@Repeated(1)})");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodClass.getMethodMultipleAnnotation(),
"@Container({@Repeated(1), @Repeated(2)})");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodClass.getMethodSingleAnnotation(),
"@Repeated(1)");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodClass.getMethodStaticSingleAnnotation(),
"@Repeated(1)");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(),
"@Repeated(1)");
}
+ private static class ConstructorClass {
+ // No annotations.
+ public ConstructorClass(Integer parameter1, Integer parameter2) {}
+
+ // Annotations.
+ public ConstructorClass(@AnnotationB @AnnotationD String parameter1,
+ @AnnotationC @AnnotationD String parameter2) {}
+ }
+
+ public void testConstructorGetParameterAnnotations() throws Exception {
+ Constructor constructorWithoutAnnotatedParameters =
+ ConstructorClass.class.getDeclaredConstructor(Integer.class, Integer.class);
+ Annotation[][] noParameterAnnotations = getParameterAnnotations(
+ constructorWithoutAnnotatedParameters, 2);
+ assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
+ assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
+
+ Constructor constructorWithAnnotatedParameters =
+ ConstructorClass.class.getDeclaredConstructor(String.class, String.class);
+ Annotation[][] parameterAnnotations = getParameterAnnotations(
+ constructorWithAnnotatedParameters, 2);
+ assertEquals(set(AnnotationB.class, AnnotationD.class),
+ annotationsToTypes(parameterAnnotations[0]));
+ assertEquals(set(AnnotationC.class, AnnotationD.class),
+ annotationsToTypes(parameterAnnotations[1]));
+ }
+
private static class AnnotatedConstructorClass {
public AnnotatedConstructorClass(Boolean p0) {}
@@ -207,30 +205,95 @@
}
public void testConstructorGetParameterAnnotations_repeated() throws Exception {
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
EXPECT_EMPTY);
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
"@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
"@Container({@Repeated(1)})");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
"@Container({@Repeated(1), @Repeated(2)})");
- assertParameter0Annotations(
+ assertOnlyParameterAnnotations(
AnnotatedConstructorClass.getConstructorSingleAnnotation(),
"@Repeated(1)");
}
- private static void assertParameter0Annotations(
+ /**
+ * As an inner class the constructor will actually have two parameters: the first, referencing
+ * the enclosing object, is inserted by the compiler.
+ */
+ class InnerClass {
+ InnerClass(@AnnotationA String p1) {}
+ }
+
+ /** Special case testing for a compiler-generated constructor parameter. JLS 8.8.1, JLS 13.1. */
+ public void testImplicitConstructorParameters_innerClass() throws Exception {
+ Constructor<InnerClass> constructor =
+ InnerClass.class.getDeclaredConstructor(
+ ExecutableParameterTest.class, String.class);
+
+ // The parameter annotation code behaves as if there are two parameters.
+ Annotation[][] annotations = getParameterAnnotations(constructor, 2);
+ assertAnnotationsMatch(annotations[0], new String[0]);
+ assertAnnotationsMatch(annotations[1], new String[] { "@AnnotationA" });
+ }
+
+ static abstract class AnonymousBaseClass {
+ public AnonymousBaseClass(@AnnotationA String p1) {}
+ }
+
+ /** Special case testing for a compiler-generated constructor parameter. JLS 13.1 */
+ public void testImplicitConstructorParameters_anonymousClass() throws Exception {
+ /*
+ * As an anonymous class the constructor will actually have two parameters: the first,
+ * referencing the enclosing object, is inserted by the compiler.
+ */
+ AnonymousBaseClass anonymousClassInstance = new AnonymousBaseClass("p1") {};
+
+ Constructor<? extends AnonymousBaseClass> constructor =
+ anonymousClassInstance.getClass().getDeclaredConstructor(
+ ExecutableParameterTest.class, String.class);
+ // The parameter annotation code behaves as if there are two parameters.
+ Annotation[][] annotations = getParameterAnnotations(constructor, 2);
+ assertAnnotationsMatch(annotations[0], new String[0]);
+ assertAnnotationsMatch(annotations[1], new String[0]);
+ }
+
+ /**
+ * A static inner / nested member class will not have synthetic parameters and should behave
+ * like a top-level class.
+ */
+ static class StaticInnerClass {
+ StaticInnerClass(@AnnotationA String p1) {}
+ }
+
+ /** Special case testing for a compiler-generated constructor parameter. */
+ public void testImplicitConstructorParameters_staticInnerClass() throws Exception {
+ Constructor<StaticInnerClass> constructor =
+ StaticInnerClass.class.getDeclaredConstructor(String.class);
+ Parameter[] parameters = constructor.getParameters();
+ assertEquals(1, parameters.length);
+
+ Annotation[][] annotations = getParameterAnnotations(constructor, 1);
+ assertAnnotationsMatch(annotations[0], new String[] { "@AnnotationA" });
+ }
+
+ private static void assertOnlyParameterAnnotations(
Executable executable, String... expectedAnnotationStrings) throws Exception {
- Annotation[][] allAnnotations = executable.getParameterAnnotations();
- final int expectedParameterCount = 1;
- assertEquals(expectedParameterCount, allAnnotations.length);
+ Annotation[][] allAnnotations = getParameterAnnotations(executable, 1);
Annotation[] p0Annotations = allAnnotations[0];
assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings);
}
+
+ private static Annotation[][] getParameterAnnotations(
+ Executable executable, int expectedParameterAnnotationsSize) {
+ Annotation[][] allAnnotations = executable.getParameterAnnotations();
+ assertEquals(expectedParameterAnnotationsSize, allAnnotations.length);
+ return allAnnotations;
+ }
}