diff options
20 files changed, 1851 insertions, 6 deletions
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java index 1950bf34d5..f690295635 100644 --- a/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java +++ b/luni/src/test/java/libcore/java/lang/reflect/ReflectionTest.java @@ -16,22 +16,28 @@ package libcore.java.lang.reflect; +import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.AbstractCollection; import java.util.AbstractList; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.RandomAccess; import java.util.Set; -import junit.framework.Assert; import junit.framework.TestCase; public final class ReflectionTest extends TestCase { @@ -430,4 +436,215 @@ public final class ReflectionTest extends TestCase { void foobar() {} } } + + public void testGetEnclosingClass() { + assertNull(ReflectionTest.class.getEnclosingClass()); + assertEquals(ReflectionTest.class, Foo.class.getEnclosingClass()); + assertEquals(ReflectionTest.class, HasMemberClassesInterface.class.getEnclosingClass()); + assertEquals(HasMemberClassesInterface.class, + HasMemberClassesInterface.D.class.getEnclosingClass()); + assertEquals(ReflectionTest.class, Foo.class.getEnclosingClass()); + } + + public void testGetDeclaringClass() { + assertNull(ReflectionTest.class.getDeclaringClass()); + assertEquals(ReflectionTest.class, Foo.class.getDeclaringClass()); + assertEquals(ReflectionTest.class, HasMemberClassesInterface.class.getDeclaringClass()); + assertEquals(HasMemberClassesInterface.class, + HasMemberClassesInterface.D.class.getDeclaringClass()); + } + + public void testGetEnclosingClassIsTransitiveForClassesDefinedInAMethod() { + class C {} + assertEquals(ReflectionTest.class, C.class.getEnclosingClass()); + } + + public void testGetDeclaringClassIsNotTransitiveForClassesDefinedInAMethod() { + class C {} + assertEquals(null, C.class.getDeclaringClass()); + } + + public void testGetEnclosingMethodIsNotTransitive() { + class C { + class D {} + } + assertEquals(null, C.D.class.getEnclosingMethod()); + } + + private static final Object staticAnonymous = new Object() {}; + + public void testStaticFieldAnonymousClass() { + // The class declared in the <clinit> is enclosed by the <clinit>'s class. + // http://b/11245138 + assertEquals(ReflectionTest.class, staticAnonymous.getClass().getEnclosingClass()); + // However, because it is anonymous, it has no declaring class. + // https://code.google.com/p/android/issues/detail?id=61003 + assertNull(staticAnonymous.getClass().getDeclaringClass()); + // Because the class is declared in <clinit> which is not exposed through reflection, + // it has no enclosing method or constructor. + assertNull(staticAnonymous.getClass().getEnclosingMethod()); + assertNull(staticAnonymous.getClass().getEnclosingConstructor()); + } + + public void testGetEnclosingMethodOfTopLevelClass() { + assertNull(ReflectionTest.class.getEnclosingMethod()); + } + + public void testGetEnclosingConstructorOfTopLevelClass() { + assertNull(ReflectionTest.class.getEnclosingConstructor()); + } + + public void testClassEnclosedByConstructor() throws Exception { + Foo foo = new Foo("string"); + assertEquals(Foo.class, foo.c.getEnclosingClass()); + assertEquals(Foo.class.getDeclaredConstructor(String.class), + foo.c.getEnclosingConstructor()); + assertNull(foo.c.getEnclosingMethod()); + assertNull(foo.c.getDeclaringClass()); + } + + public void testClassEnclosedByMethod() throws Exception { + Foo foo = new Foo(); + foo.foo("string"); + assertEquals(Foo.class, foo.c.getEnclosingClass()); + assertNull(foo.c.getEnclosingConstructor()); + assertEquals(Foo.class.getDeclaredMethod("foo", String.class), + foo.c.getEnclosingMethod()); + assertNull(foo.c.getDeclaringClass()); + } + + public void testGetClasses() throws Exception { + // getClasses() doesn't include classes inherited from interfaces! + assertSetEquals(HasMemberClasses.class.getClasses(), + HasMemberClassesSuperclass.B.class, HasMemberClasses.H.class); + } + + public void testGetDeclaredClasses() throws Exception { + assertSetEquals(HasMemberClasses.class.getDeclaredClasses(), + HasMemberClasses.G.class, HasMemberClasses.H.class, HasMemberClasses.I.class, + HasMemberClasses.J.class, HasMemberClasses.K.class, HasMemberClasses.L.class); + } + + public void testConstructorGetExceptions() throws Exception { + assertSetEquals(HasThrows.class.getConstructor().getExceptionTypes(), + IOException.class, InvocationTargetException.class, IllegalStateException.class); + assertSetEquals(HasThrows.class.getConstructor(Void.class).getExceptionTypes()); + } + + public void testClassMethodGetExceptions() throws Exception { + assertSetEquals(HasThrows.class.getMethod("foo").getExceptionTypes(), + IOException.class, InvocationTargetException.class, IllegalStateException.class); + assertSetEquals(HasThrows.class.getMethod("foo", Void.class).getExceptionTypes()); + } + + public void testProxyMethodGetExceptions() throws Exception { + InvocationHandler emptyInvocationHandler = new InvocationHandler() { + @Override public Object invoke(Object proxy, Method method, Object[] args) { + return null; + } + }; + + Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), + new Class[] { ThrowsInterface.class }, emptyInvocationHandler); + assertSetEquals(proxy.getClass().getMethod("foo").getExceptionTypes(), + IOException.class, InvocationTargetException.class, IllegalStateException.class); + assertSetEquals(proxy.getClass().getMethod("foo", Void.class).getExceptionTypes()); + } + + public void testClassModifiers() { + int modifiers = ReflectionTest.class.getModifiers(); + assertTrue(Modifier.isPublic(modifiers)); + assertFalse(Modifier.isProtected(modifiers)); + assertFalse(Modifier.isPrivate(modifiers)); + assertFalse(Modifier.isAbstract(modifiers)); + assertFalse(Modifier.isStatic(modifiers)); + assertTrue(Modifier.isFinal(modifiers)); + assertFalse(Modifier.isStrict(modifiers)); + } + + public void testInnerClassModifiers() { + int modifiers = Foo.class.getModifiers(); + assertFalse(Modifier.isPublic(modifiers)); + assertFalse(Modifier.isProtected(modifiers)); + assertTrue(Modifier.isPrivate(modifiers)); + assertFalse(Modifier.isAbstract(modifiers)); + assertTrue(Modifier.isStatic(modifiers)); + assertFalse(Modifier.isFinal(modifiers)); + assertFalse(Modifier.isStrict(modifiers)); + } + + public void testAnonymousClassModifiers() { + int modifiers = staticAnonymous.getClass().getModifiers(); + assertFalse(Modifier.isPublic(modifiers)); + assertFalse(Modifier.isProtected(modifiers)); + assertFalse(Modifier.isPrivate(modifiers)); + assertFalse(Modifier.isAbstract(modifiers)); + assertTrue(Modifier.isStatic(modifiers)); + assertFalse(Modifier.isFinal(modifiers)); + assertFalse(Modifier.isStrict(modifiers)); + } + + public void testInnerClassName() { + assertEquals("ReflectionTest", ReflectionTest.class.getSimpleName()); + assertEquals("Foo", Foo.class.getSimpleName()); + assertEquals("", staticAnonymous.getClass().getSimpleName()); + } + + private static class Foo { + Class<?> c; + private Foo() { + } + private Foo(String s) { + c = new Object() {}.getClass(); + } + private Foo(int i) { + c = new Object() {}.getClass(); + } + private void foo(String s) { + c = new Object() {}.getClass(); + } + private void foo(int i) { + c = new Object() {}.getClass(); + } + } + + static class HasMemberClassesSuperclass { + class A {} + public class B {} + static class C {} + } + + public interface HasMemberClassesInterface { + class D {} + public class E {} + static class F {} + } + + public static class HasMemberClasses extends HasMemberClassesSuperclass + implements HasMemberClassesInterface { + class G {} + public class H {} + static class I {} + enum J {} + interface K {} + @interface L {} + } + + public static class HasThrows { + public HasThrows() throws IOException, InvocationTargetException, IllegalStateException {} + public HasThrows(Void v) {} + public void foo() throws IOException, InvocationTargetException, IllegalStateException {} + public void foo(Void v) {} + } + + public static interface ThrowsInterface { + void foo() throws IOException, InvocationTargetException, IllegalStateException; + void foo(Void v); + } + + private void assertSetEquals(Object[] actual, Object... expected) { + Set<Object> actualSet = new HashSet<Object>(Arrays.asList(actual)); + Set<Object> expectedSet = new HashSet<Object>(Arrays.asList(expected)); + assertEquals(expectedSet, actualSet); + } } 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 new file mode 100644 index 0000000000..ec574699b6 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.StringJoiner; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +/** + * Utility methods and annotation definitions for use when testing implementations of + * AnnotatedElement. + * + * <p>For compactness, the repeated annotation methods that take strings use a format based on Java + * syntax rather than the toString() of annotations. For example, "@Repeated(1)" rather than + * "@libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated(value=1)". Use + * {@link #EXPECT_EMPTY} to indicate "no annotationed expected". + */ +public class AnnotatedElementTestSupport { + + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationA {} + + @Inherited + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationB {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationC {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationD {} + + @Retention(RetentionPolicy.RUNTIME) + @Inherited + @Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, + ElementType.PARAMETER, ElementType.PACKAGE }) + public @interface Container { + Repeated[] value(); + } + + @Repeatable(Container.class) + @Retention(RetentionPolicy.RUNTIME) + @Inherited + @Target({ ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, + ElementType.PARAMETER, ElementType.PACKAGE }) + public @interface Repeated { + int value(); + } + + /** + * A named constant that can be used with assert methods below that take + * "String[] expectedAnnotationStrings" as their final argument to indicate "none". + */ + public static final String[] EXPECT_EMPTY = new String[0]; + + private AnnotatedElementTestSupport() { + } + + /** + * Test the {@link AnnotatedElement} methods associated with "presence". i.e. methods that + * deal with annotations being "present" (i.e. "direct" or "inherited" annotations, not + * "indirect"). + * + * <p>Asserts that calling {@link AnnotatedElement#getAnnotations()} on the supplied element + * returns annotations of the supplied expected classes. + * + * <p>Where the expected classes contains some subset from + * {@link AnnotationA}, {@link AnnotationB} and {@link AnnotationC}, this method also asserts + * that {@link AnnotatedElement#isAnnotationPresent(Class)} and + * {@link AnnotatedElement#getAnnotation(Class)} works as expected. + * + * <p>This method also confirms that {@link AnnotatedElement#isAnnotationPresent(Class)} and + * {@link AnnotatedElement#getAnnotation(Class)} work correctly with a {@code null} argument. + */ + static void checkAnnotatedElementPresentMethods( + AnnotatedElement element, Class<? extends Annotation>... expectedAnnotations) { + Set<Class<? extends Annotation>> actualTypes = annotationsToTypes(element.getAnnotations()); + Set<Class<? extends Annotation>> expectedTypes = set(expectedAnnotations); + assertEquals(expectedTypes, actualTypes); + + // getAnnotations() should be consistent with isAnnotationPresent() and getAnnotation() + assertPresent(expectedTypes.contains(AnnotationA.class), element, AnnotationA.class); + assertPresent(expectedTypes.contains(AnnotationB.class), element, AnnotationB.class); + assertPresent(expectedTypes.contains(AnnotationC.class), element, AnnotationC.class); + + try { + element.isAnnotationPresent(null); + fail(); + } catch (NullPointerException expected) { + } + + try { + element.getAnnotation(null); + fail(); + } catch (NullPointerException expected) { + } + } + + /** + * Test the {@link AnnotatedElement} methods associated with "direct" annotations. + * + * <p>Asserts that calling {@link AnnotatedElement#getDeclaredAnnotations()} on the supplied + * element returns annotations of the supplied expected classes. + * + * <p>Where the expected classes contains some subset from + * {@link AnnotationA}, {@link AnnotationB} and {@link AnnotationC}, this method also asserts + * that {@link AnnotatedElement#getDeclaredAnnotation(Class)} works as expected. + * + * <p>This method also confirms that {@link AnnotatedElement#isAnnotationPresent(Class)} and + * {@link AnnotatedElement#getAnnotation(Class)} work correctly with a {@code null} argument. + */ + static void checkAnnotatedElementDirectMethods( + AnnotatedElement element, + Class<? extends Annotation>... expectedDeclaredAnnotations) { + Set<Class<? extends Annotation>> actualTypes = annotationsToTypes(element.getDeclaredAnnotations()); + Set<Class<? extends Annotation>> expectedTypes = set(expectedDeclaredAnnotations); + assertEquals(expectedTypes, actualTypes); + + assertDeclared(expectedTypes.contains(AnnotationA.class), element, AnnotationA.class); + assertDeclared(expectedTypes.contains(AnnotationB.class), element, AnnotationB.class); + assertDeclared(expectedTypes.contains(AnnotationC.class), element, AnnotationC.class); + + try { + element.getDeclaredAnnotation(null); + fail(); + } catch (NullPointerException expected) { + } + } + + /** + * Extracts the annotation types ({@link Annotation#annotationType()} from the supplied + * annotations. + */ + static Set<Class<? extends Annotation>> annotationsToTypes(Annotation[] annotations) { + Set<Class<? extends Annotation>> result = new HashSet<Class<? extends Annotation>>(); + for (Annotation annotation : annotations) { + result.add(annotation.annotationType()); + } + return result; + } + + private static void assertPresent(boolean present, AnnotatedElement element, + Class<? extends Annotation> annotation) { + if (present) { + assertNotNull(element.getAnnotation(annotation)); + assertTrue(element.isAnnotationPresent(annotation)); + } else { + assertNull(element.getAnnotation(annotation)); + assertFalse(element.isAnnotationPresent(annotation)); + } + } + + private static void assertDeclared(boolean present, AnnotatedElement element, + Class<? extends Annotation> annotation) { + if (present) { + assertNotNull(element.getDeclaredAnnotation(annotation)); + } else { + assertNull(element.getDeclaredAnnotation(annotation)); + } + } + + @SafeVarargs + static <T> Set<T> set(T... instances) { + return new HashSet<>(Arrays.asList(instances)); + } + + /** + * Asserts that {@link AnnotatedElement#isAnnotationPresent(Class)} returns the expected result. + */ + static void assertIsAnnotationPresent( + AnnotatedElement element, Class<? extends Annotation> annotationType, + boolean expected) { + assertEquals("element.isAnnotationPresent() for " + element + " and " + annotationType, + expected, element.isAnnotationPresent(annotationType)); + } + + /** + * Asserts that {@link AnnotatedElement#getDeclaredAnnotation(Class)} returns the expected + * result. The result is specified using a String. See {@link AnnotatedElementTestSupport} for + * the string syntax. + */ + static void assertGetDeclaredAnnotation(AnnotatedElement annotatedElement, + Class<? extends Annotation> annotationType, String expectedAnnotationString) { + Annotation annotation = annotatedElement.getDeclaredAnnotation(annotationType); + assertAnnotationMatches(annotation, expectedAnnotationString); + } + + /** + * Asserts that {@link AnnotatedElement#getDeclaredAnnotationsByType(Class)} returns the + * expected result. The result is specified using a String. See + * {@link AnnotatedElementTestSupport} for the string syntax. + */ + static void assertGetDeclaredAnnotationsByType( + AnnotatedElement annotatedElement, Class<? extends Annotation> annotationType, + String[] expectedAnnotationStrings) { + Annotation[] annotations = annotatedElement.getDeclaredAnnotationsByType(annotationType); + assertAnnotationsMatch(annotations, expectedAnnotationStrings); + } + + /** + * Asserts that {@link AnnotatedElement#getAnnotationsByType(Class)} returns the + * expected result. The result is specified using a String. See + * {@link AnnotatedElementTestSupport} for the string syntax. + */ + static void assertGetAnnotationsByType(AnnotatedElement annotatedElement, + Class<? extends Annotation> annotationType, String[] expectedAnnotationStrings) + throws Exception { + Annotation[] annotations = annotatedElement.getAnnotationsByType(annotationType); + assertAnnotationsMatch(annotations, expectedAnnotationStrings); + } + + private static void assertAnnotationMatches( + Annotation annotation, String expectedAnnotationString) { + if (expectedAnnotationString == null) { + assertNull(annotation); + } else { + assertNotNull(annotation); + assertEquals(expectedAnnotationString, createAnnotationTestString(annotation)); + } + } + + /** + * Asserts that the supplied annotations match the expectation Strings. See + * {@link AnnotatedElementTestSupport} for the string syntax. + */ + static void assertAnnotationsMatch(Annotation[] annotations, + String[] expectedAnnotationStrings) { + + // Due to Android's dex format insisting that Annotations are sorted by name the ordering of + // annotations is determined by the (simple?) name of the Annotation, not just the order + // that they are defined in the source. Tests have to be sensitive to that when handling + // mixed usage of "Container" and "Repeated" - the "Container" annotations will be + // discovered before "Repeated" due to their sort ordering. + // + // This code assumes that repeated annotations with the same name will be specified in the + // source their natural sort order when attributes are considered, just to make the testing + // simpler. + // e.g. @Repeated(1) @Repeated(2), never @Repeated(2) @Repeated(1) + + // Sorting the expected and actual strings _should_ work providing the assumptions above + // hold. It may mask random ordering issues but it's harder to deal with that while the + // source ordering is no observed. Providing no developers are ascribing meaning to the + // relative order of annotations things should be ok. + Arrays.sort(expectedAnnotationStrings); + + String[] actualAnnotationStrings = createAnnotationTestStrings(annotations); + Arrays.sort(actualAnnotationStrings); + + assertEquals( + Arrays.asList(expectedAnnotationStrings), + Arrays.asList(actualAnnotationStrings)); + } + + private static String[] createAnnotationTestStrings(Annotation[] annotations) { + String[] annotationStrings = new String[annotations.length]; + for (int i = 0; i < annotations.length; i++) { + annotationStrings[i] = createAnnotationTestString(annotations[i]); + } + return annotationStrings; + } + + private static String createAnnotationTestString(Annotation annotation) { + return "@" + annotation.annotationType().getSimpleName() + createArgumentsTestString( + annotation); + } + + private static String createArgumentsTestString(Annotation annotation) { + if (annotation instanceof Repeated) { + Repeated repeated = (Repeated) annotation; + return "(" + repeated.value() + ")"; + } else if (annotation instanceof Container) { + Container container = (Container) annotation; + String[] repeatedValues = createAnnotationTestStrings(container.value()); + StringJoiner joiner = new StringJoiner(", ", "{", "}"); + for (String repeatedValue : repeatedValues) { + joiner.add(repeatedValue); + } + String repeatedValuesString = joiner.toString(); + return "(" + repeatedValuesString + ")"; + } + throw new AssertionError("Unknown annotation: " + annotation); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/Annotations57649Test.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/Annotations57649Test.java index 60e294bd6c..94c265eae9 100644 --- a/luni/src/test/java/libcore/java/lang/reflect/Annotations57649Test.java +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/Annotations57649Test.java @@ -1,4 +1,4 @@ -package libcore.java.lang.reflect; +package libcore.java.lang.reflect.annotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java new file mode 100644 index 0000000000..a694981c70 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotationsTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; + +import dalvik.system.VMRuntime; + +/** + * Tests for the behavior of Annotation instances at runtime. + */ +public class AnnotationsTest extends TestCase { + + enum Breakfast { WAFFLES, PANCAKES } + + @Retention(RetentionPolicy.RUNTIME) + public @interface HasDefaultsAnnotation { + byte a() default 5; + short b() default 6; + int c() default 7; + long d() default 8; + float e() default 9.0f; + double f() default 10.0; + char g() default 'k'; + boolean h() default true; + Breakfast i() default Breakfast.WAFFLES; + AnnotationA j() default @AnnotationA(); + String k() default "maple"; + Class l() default AnnotationB.class; + int[] m() default { 1, 2, 3 }; + Breakfast[] n() default { Breakfast.WAFFLES, Breakfast.PANCAKES }; + Breakfast o(); + int p(); + } + + public void testAnnotationDefaults() throws Exception { + assertEquals((byte) 5, defaultValue("a")); + assertEquals((short) 6, defaultValue("b")); + assertEquals(7, defaultValue("c")); + assertEquals(8L, defaultValue("d")); + assertEquals(9.0f, defaultValue("e")); + assertEquals(10.0, defaultValue("f")); + assertEquals('k', defaultValue("g")); + assertEquals(true, defaultValue("h")); + assertEquals(Breakfast.WAFFLES, defaultValue("i")); + assertEquals("@" + AnnotationA.class.getName() + "()", defaultValue("j").toString()); + assertEquals("maple", defaultValue("k")); + assertEquals(AnnotationB.class, defaultValue("l")); + assertEquals("[1, 2, 3]", Arrays.toString((int[]) defaultValue("m"))); + assertEquals("[WAFFLES, PANCAKES]", Arrays.toString((Breakfast[]) defaultValue("n"))); + assertEquals(null, defaultValue("o")); + assertEquals(null, defaultValue("p")); + } + + private static Object defaultValue(String name) throws NoSuchMethodException { + return HasDefaultsAnnotation.class.getMethod(name).getDefaultValue(); + } + + @Retention(RetentionPolicy.CLASS) + public @interface ClassRetentionAnnotation {} + + @Retention(RetentionPolicy.RUNTIME) + public @interface RuntimeRetentionAnnotation {} + + @Retention(RetentionPolicy.SOURCE) + public @interface SourceRetentionAnnotation {} + + @ClassRetentionAnnotation @RuntimeRetentionAnnotation @SourceRetentionAnnotation + public static class RetentionAnnotations {} + + public void testRetentionPolicy() { + // b/29500035 + int savedTargetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); + try { + // Test N and later behavior + VMRuntime.getRuntime().setTargetSdkVersion(24); + Annotation classRetentionAnnotation = + RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class); + assertNull(classRetentionAnnotation); + + // Test pre-N behavior + VMRuntime.getRuntime().setTargetSdkVersion(23); + classRetentionAnnotation = + RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class); + assertNotNull(classRetentionAnnotation); + } finally { + VMRuntime.getRuntime().setTargetSdkVersion(savedTargetSdkVersion); + } + assertNotNull(RetentionAnnotations.class.getAnnotation(RuntimeRetentionAnnotation.class)); + assertNull(RetentionAnnotations.class.getAnnotation(SourceRetentionAnnotation.class)); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ClassTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ClassTest.java new file mode 100644 index 0000000000..5488ed19d0 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ClassTest.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Inherited; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementDirectMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class ClassTest extends TestCase { + + public void setUp() throws Exception { + super.setUp(); + // Required by all the tests. + Repeated.class.isAnnotationPresent(Inherited.class); + } + + @AnnotationA + @AnnotationB + private static class Type { + } + + public static class ExtendsType extends Type {} + + public void testClassDirectAnnotations() { + checkAnnotatedElementPresentMethods(Type.class, AnnotationA.class, AnnotationB.class); + checkAnnotatedElementDirectMethods(Type.class, AnnotationA.class, AnnotationB.class); + } + + public void testClassInheritedAnnotations() { + checkAnnotatedElementPresentMethods(ExtendsType.class, AnnotationB.class); + checkAnnotatedElementDirectMethods(ExtendsType.class); + } + + @Repeated(1) + private static class SingleAnnotation {} + + @Repeated(1) + @Repeated(2) + private static class MultipleAnnotation {} + + @Container({@Repeated(1)}) + private static class MultipleAnnotationExplicitSingle {} + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + private static class MultipleAnnotationOddity {} + + private static class NoAnnotation {} + + private static class InheritedNoNewAnnotation extends SingleAnnotation {} + + @Repeated(2) + private static class InheritedSingleWithNewSingleAnnotation extends SingleAnnotation {} + + @Repeated(2) + @Repeated(3) + private static class InheritedSingleWithNewMultipleAnnotations extends SingleAnnotation {} + + @Repeated(2) + private static class InheritedMultipleWithNewSingleAnnotation extends MultipleAnnotation {} + + @Repeated(2) + @Repeated(3) + private static class InheritedMultipleWithNewMultipleAnnotations extends MultipleAnnotation {} + + public void testIsAnnotationPresent() throws Exception { + Class<Repeated> repeated = Repeated.class; + assertIsAnnotationPresent(NoAnnotation.class, repeated, false); + assertIsAnnotationPresent(SingleAnnotation.class, repeated, true); + assertIsAnnotationPresent(MultipleAnnotation.class, repeated, false); + assertIsAnnotationPresent(MultipleAnnotationExplicitSingle.class, repeated, false); + assertIsAnnotationPresent(MultipleAnnotationOddity.class, repeated, true); + assertIsAnnotationPresent(InheritedNoNewAnnotation.class, repeated, true); + assertIsAnnotationPresent(InheritedSingleWithNewSingleAnnotation.class, repeated, true); + assertIsAnnotationPresent(InheritedSingleWithNewMultipleAnnotations.class, repeated, true); + assertIsAnnotationPresent(InheritedMultipleWithNewSingleAnnotation.class, repeated, true); + assertIsAnnotationPresent(InheritedMultipleWithNewMultipleAnnotations.class, repeated, + false); + + Class<Container> container = Container.class; + assertIsAnnotationPresent(NoAnnotation.class, repeated, false); + assertIsAnnotationPresent(SingleAnnotation.class, container, false); + assertIsAnnotationPresent(MultipleAnnotation.class, container, true); + assertIsAnnotationPresent(MultipleAnnotationExplicitSingle.class, container, true); + assertIsAnnotationPresent(MultipleAnnotationOddity.class, container, true); + assertIsAnnotationPresent(InheritedNoNewAnnotation.class, container, false); + assertIsAnnotationPresent(InheritedSingleWithNewSingleAnnotation.class, container, false); + assertIsAnnotationPresent(InheritedSingleWithNewMultipleAnnotations.class, container, true); + assertIsAnnotationPresent(InheritedMultipleWithNewSingleAnnotation.class, container, true); + assertIsAnnotationPresent(InheritedMultipleWithNewMultipleAnnotations.class, container, + true); + } + + public void testGetDeclaredAnnotation() throws Exception { + Class<Repeated> repeated = Repeated.class; + assertGetDeclaredAnnotation(NoAnnotation.class, repeated, null); + assertGetDeclaredAnnotation(SingleAnnotation.class, repeated, "@Repeated(1)"); + assertGetDeclaredAnnotation(MultipleAnnotation.class, repeated, null); + assertGetDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, repeated, null); + assertGetDeclaredAnnotation(MultipleAnnotationOddity.class, repeated, "@Repeated(1)"); + assertGetDeclaredAnnotation(InheritedNoNewAnnotation.class, repeated, null); + assertGetDeclaredAnnotation(InheritedSingleWithNewSingleAnnotation.class, repeated, + "@Repeated(2)"); + assertGetDeclaredAnnotation(InheritedSingleWithNewMultipleAnnotations.class, repeated, + null); + assertGetDeclaredAnnotation(InheritedMultipleWithNewSingleAnnotation.class, repeated, + "@Repeated(2)"); + assertGetDeclaredAnnotation(InheritedMultipleWithNewMultipleAnnotations.class, repeated, + null); + + Class<Container> container = Container.class; + assertGetDeclaredAnnotation(NoAnnotation.class, container, null); + assertGetDeclaredAnnotation(SingleAnnotation.class, container, null); + assertGetDeclaredAnnotation(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotation(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotation(InheritedNoNewAnnotation.class, container, null); + assertGetDeclaredAnnotation(InheritedSingleWithNewSingleAnnotation.class, container, null); + assertGetDeclaredAnnotation(InheritedSingleWithNewMultipleAnnotations.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotation(InheritedMultipleWithNewSingleAnnotation.class, container, + null); + assertGetDeclaredAnnotation(InheritedMultipleWithNewMultipleAnnotations.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + NoAnnotation.class, repeated, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + SingleAnnotation.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotation.class, repeated, new String[] { "@Repeated(1)", "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationExplicitSingle.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationOddity.class, repeated, + new String[] { "@Repeated(1)", "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedNoNewAnnotation.class, repeated, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + + Class<Container> container = Container.class; + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + NoAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + SingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotation.class, container, + new String[] { "@Container({@Repeated(1), @Repeated(2)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationExplicitSingle.class, container, + new String[] { "@Container({@Repeated(1)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + MultipleAnnotationOddity.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedNoNewAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + } + + public void testGetAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + AnnotatedElementTestSupport.assertGetAnnotationsByType( + NoAnnotation.class, repeated, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + SingleAnnotation.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotation.class, repeated, new String[] { "@Repeated(1)", "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationExplicitSingle.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationOddity.class, repeated, + new String[] { "@Repeated(1)", "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedNoNewAnnotation.class, repeated, new String[] { "@Repeated(1)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, repeated, + new String[] { "@Repeated(2)" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, repeated, + new String[] { "@Repeated(2)", "@Repeated(3)" }); + + Class<Container> container = Container.class; + AnnotatedElementTestSupport.assertGetAnnotationsByType( + NoAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + SingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotation.class, container, + new String[] { "@Container({@Repeated(1), @Repeated(2)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationExplicitSingle.class, container, + new String[] { "@Container({@Repeated(1)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + MultipleAnnotationOddity.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedNoNewAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewSingleAnnotation.class, container, EXPECT_EMPTY); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedSingleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewSingleAnnotation.class, container, + new String[] { "@Container({@Repeated(1), @Repeated(2)})" }); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + InheritedMultipleWithNewMultipleAnnotations.class, container, + new String[] { "@Container({@Repeated(2), @Repeated(3)})" }); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ConstructorTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ConstructorTest.java new file mode 100644 index 0000000000..828b6016f2 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ConstructorTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class ConstructorTest extends TestCase { + + private static class Type { + @AnnotationA + @AnnotationC + public Type() {} + } + + public void testConstructorAnnotations() throws Exception { + Constructor<Type> constructor = Type.class.getConstructor(); + checkAnnotatedElementPresentMethods(constructor, AnnotationA.class, AnnotationC.class); + } + + // A class with multiple constructors that differ by their argument count. + private static class AnnotatedClass { + @Repeated(1) + public AnnotatedClass() {} + + @Repeated(1) + @Repeated(2) + public AnnotatedClass(int a) {} + + @Container({@Repeated(1)}) + public AnnotatedClass(int a, int b) {} + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + public AnnotatedClass(int a, int b, int c) {} + + public AnnotatedClass(int a, int b, int c, int d) {} + } + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + checkDeclaredAnnotation(c, 4, repeated, null); + checkDeclaredAnnotation(c, 3, repeated, "@Repeated(1)"); + checkDeclaredAnnotation(c, 2, repeated, null); + checkDeclaredAnnotation(c, 1, repeated, null); + checkDeclaredAnnotation(c, 0, repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + checkDeclaredAnnotation(c, 4, container, null); + checkDeclaredAnnotation(c, 3, container, "@Container({@Repeated(2), @Repeated(3)})"); + checkDeclaredAnnotation(c, 2, container, "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(c, 1, container, "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(c, 0, container, null); + } + + private static void checkDeclaredAnnotation(Class<?> c, int constructorArgCount, + Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + Constructor constructor = getConstructor(c, constructorArgCount); + + // isAnnotationPresent + assertIsAnnotationPresent(constructor, annotationType, + expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(constructor, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetDeclaredAnnotationsByType(c, 4, repeated, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, 3, repeated, + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetDeclaredAnnotationsByType(c, 2, repeated, "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(c, 1, repeated, "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(c, 0, repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetDeclaredAnnotationsByType(c, 4, container, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, 3, container, + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotationsByType(c, 2, container, "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(c, 1, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(c, 0, container, EXPECT_EMPTY); + } + + private static void assertGetDeclaredAnnotationsByType(Class<?> c, int constructorArgCount, + Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Constructor<?> constructor = getConstructor(c, constructorArgCount); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + constructor, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetAnnotationsByType(c, 4, repeated, EXPECT_EMPTY); + assertGetAnnotationsByType(c, 3, repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetAnnotationsByType(c, 2, repeated, "@Repeated(1)"); + assertGetAnnotationsByType(c, 1, repeated, "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(c, 0, repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetAnnotationsByType(c, 4, container, EXPECT_EMPTY); + assertGetAnnotationsByType(c, 3, container, "@Container({@Repeated(2), @Repeated(3)})"); + assertGetAnnotationsByType(c, 2, container, "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(c, 1, container, "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(c, 0, container, EXPECT_EMPTY); + } + + private static void assertGetAnnotationsByType(Class<?> c, int constructorArgCount, + Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Constructor<?> constructor = getConstructor(c, constructorArgCount); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + constructor, annotationType, expectedAnnotationStrings); + } + + private static Constructor<?> getConstructor(Class<?> c, int constructorArgCount) + throws NoSuchMethodException { + + Class<?>[] args = new Class[constructorArgCount]; + for (int i = 0; i < constructorArgCount; i++) { + args[i] = Integer.TYPE; + } + return c.getDeclaredConstructor(args); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/FieldTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/FieldTest.java new file mode 100644 index 0000000000..8ab7d8ea05 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/FieldTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class FieldTest extends TestCase { + + private static class Type { + @AnnotationA + @AnnotationD + public String field; + } + + public void testFieldAnnotations() throws Exception { + Field field = Type.class.getField("field"); + checkAnnotatedElementPresentMethods(field, AnnotationA.class, AnnotationD.class); + } + + private static class AnnotatedClass { + @Repeated(1) + private Object singleAnnotation; + + @Repeated(1) + @Repeated(2) + private Object multipleAnnotation; + + @Container({@Repeated(1)}) + private Object multipleAnnotationExplicitSingle; + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + private Object multipleAnnotationOddity; + + private Object noAnnotation; + } + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + checkDeclaredAnnotation(c, "noAnnotation", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", repeated, "@Repeated(1)"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotation", repeated, null); + checkDeclaredAnnotation(c, "singleAnnotation", repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + checkDeclaredAnnotation(c, "noAnnotation", container, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", container, + "@Container({@Repeated(2), @Repeated(3)})"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", container, + "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(c, "multipleAnnotation", container, + "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(c, "singleAnnotation", container, null); + } + + private static void checkDeclaredAnnotation( + Class<?> c, String fieldName, Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + Field field = c.getDeclaredField(fieldName); + + // isAnnotationPresent + assertIsAnnotationPresent(field, annotationType, expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(field, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetDeclaredAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetDeclaredAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetDeclaredAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, String fieldName, + String... expectedAnnotationStrings) throws Exception { + Field field = c.getDeclaredField(fieldName); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + field, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, + String fieldName, String... expectedAnnotationStrings) throws Exception { + Field field = c.getDeclaredField(fieldName); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + field, annotationType, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/MethodTest.java new file mode 100644 index 0000000000..c732a9d531 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/MethodTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class MethodTest extends TestCase { + + private static class Type { + @AnnotationB + @AnnotationC + public void method(String parameter1, String parameter2) {} + } + + public void testMethodAnnotations() throws Exception { + Method method = Type.class.getMethod("method", String.class, String.class); + checkAnnotatedElementPresentMethods(method, AnnotationB.class, AnnotationC.class); + } + + private static class AnnotatedClass { + @Repeated(1) + public void singleAnnotation() {} + + @Repeated(1) + @Repeated(2) + public void multipleAnnotation() {} + + @Container({@Repeated(1)}) + public void multipleAnnotationExplicitSingle() {} + + @Repeated(1) + @Container({@Repeated(2), @Repeated(3)}) + public void multipleAnnotationOddity() {} + + public void noAnnotation() {} + } + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + checkDeclaredAnnotation(c, "noAnnotation", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", repeated, "@Repeated(1)"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", repeated, null); + checkDeclaredAnnotation(c, "multipleAnnotation", repeated, null); + checkDeclaredAnnotation(c, "singleAnnotation", repeated, "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + checkDeclaredAnnotation(c, "noAnnotation", container, null); + checkDeclaredAnnotation(c, "multipleAnnotationOddity", container, + "@Container({@Repeated(2), @Repeated(3)})"); + checkDeclaredAnnotation(c, "multipleAnnotationExplicitSingle", container, + "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(c, "multipleAnnotation", container, + "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(c, "singleAnnotation", container, null); + } + + private static void checkDeclaredAnnotation( + Class<?> c, String methodName, Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + Method method = c.getDeclaredMethod(methodName); + + // isAnnotationPresent + assertIsAnnotationPresent(method, annotationType, expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(method, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetDeclaredAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetDeclaredAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetDeclaredAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, String methodName, + String... expectedAnnotationStrings) throws Exception { + Method method = c.getDeclaredMethod(methodName); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + method, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<?> c = AnnotatedClass.class; + + Class<? extends Annotation> repeated = Repeated.class; + assertGetAnnotationsByType(c, repeated, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationOddity", + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotationExplicitSingle", + "@Repeated(1)"); + assertGetAnnotationsByType(c, repeated, "multipleAnnotation", + "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(c, repeated, "singleAnnotation", "@Repeated(1)"); + + Class<? extends Annotation> container = Container.class; + assertGetAnnotationsByType(c, container, "noAnnotation", EXPECT_EMPTY); + assertGetAnnotationsByType(c, container, "multipleAnnotationOddity", + "@Container({@Repeated(2), @Repeated(3)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(c, container, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(c, container, "singleAnnotation", EXPECT_EMPTY); + } + + private static void assertGetAnnotationsByType( + Class<?> c, Class<? extends Annotation> annotationType, + String methodName, String... expectedAnnotationStrings) throws Exception { + Method method = c.getDeclaredMethod(methodName); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + method, annotationType, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/PackageTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/PackageTest.java new file mode 100644 index 0000000000..f54a64e437 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/PackageTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; +import libcore.java.lang.reflect.annotations.multipleannotation.MultipleAnnotation; +import libcore.java.lang.reflect.annotations.multipleannotationexplicitsingle.MultipleAnnotationExplicitSingle; +import libcore.java.lang.reflect.annotations.multipleannotationoddity.MultipleAnnotationOddity; +import libcore.java.lang.reflect.annotations.noannotation.NoAnnotation; +import libcore.java.lang.reflect.annotations.singleannotation.SingleAnnotation; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent; + +public class PackageTest extends TestCase { + + // Tests for isAnnotationPresent and getDeclaredAnnotation. + public void testDeclaredAnnotation() throws Exception { + Class<Repeated> repeated = Repeated.class; + checkDeclaredAnnotation(NoAnnotation.class, repeated, null); + checkDeclaredAnnotation(SingleAnnotation.class, repeated, "@Repeated(1)"); + checkDeclaredAnnotation(MultipleAnnotation.class, repeated, null); + checkDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, repeated, null); + checkDeclaredAnnotation(MultipleAnnotationOddity.class, repeated, "@Repeated(1)"); + + Class<Container> container = Container.class; + checkDeclaredAnnotation(NoAnnotation.class, container, null); + checkDeclaredAnnotation(SingleAnnotation.class, container, null); + checkDeclaredAnnotation(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + checkDeclaredAnnotation(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + checkDeclaredAnnotation(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + private static void checkDeclaredAnnotation( + Class<?> classInPackage, Class<? extends Annotation> annotationType, + String expectedAnnotationString) throws Exception { + + Package aPackage = classInPackage.getPackage(); + // isAnnotationPresent + assertIsAnnotationPresent(aPackage, annotationType, expectedAnnotationString != null); + + // getDeclaredAnnotation + assertGetDeclaredAnnotation(aPackage, annotationType, expectedAnnotationString); + } + + public void testGetDeclaredAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + + assertGetDeclaredAnnotationsByType(NoAnnotation.class, repeated, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(SingleAnnotation.class, repeated, + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(MultipleAnnotation.class, repeated, + "@Repeated(1)", "@Repeated(2)"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationExplicitSingle.class, repeated, + "@Repeated(1)"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationOddity.class, repeated, + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + + Class<Container> container = Container.class; + assertGetDeclaredAnnotationsByType(NoAnnotation.class, container, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(SingleAnnotation.class, container, EXPECT_EMPTY); + assertGetDeclaredAnnotationsByType(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + assertGetDeclaredAnnotationsByType(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + private static void assertGetDeclaredAnnotationsByType( + Class<?> classInPackage, Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Package aPackage = classInPackage.getPackage(); + AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType( + aPackage, annotationType, expectedAnnotationStrings); + } + + public void testGetAnnotationsByType() throws Exception { + Class<Repeated> repeated = Repeated.class; + assertGetAnnotationsByType(NoAnnotation.class, repeated, EXPECT_EMPTY); + assertGetAnnotationsByType(SingleAnnotation.class, repeated, "@Repeated(1)"); + assertGetAnnotationsByType(MultipleAnnotation.class, repeated, + "@Repeated(1)", "@Repeated(2)"); + assertGetAnnotationsByType(MultipleAnnotationExplicitSingle.class, repeated, + "@Repeated(1)"); + assertGetAnnotationsByType(MultipleAnnotationOddity.class, repeated, + "@Repeated(1)", "@Repeated(2)", "@Repeated(3)"); + + Class<Container> container = Container.class; + assertGetAnnotationsByType(NoAnnotation.class, container, EXPECT_EMPTY); + assertGetAnnotationsByType(SingleAnnotation.class, container, EXPECT_EMPTY); + assertGetAnnotationsByType(MultipleAnnotation.class, container, + "@Container({@Repeated(1), @Repeated(2)})"); + assertGetAnnotationsByType(MultipleAnnotationExplicitSingle.class, container, + "@Container({@Repeated(1)})"); + assertGetAnnotationsByType(MultipleAnnotationOddity.class, container, + "@Container({@Repeated(2), @Repeated(3)})"); + } + + private static void assertGetAnnotationsByType(Class<?> classInPackage, + Class<? extends Annotation> annotationType, + String... expectedAnnotationStrings) throws Exception { + Package aPackage = classInPackage.getPackage(); + AnnotatedElementTestSupport.assertGetAnnotationsByType( + aPackage, annotationType, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java new file mode 100644 index 0000000000..f40ac9f15e --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations; + +import junit.framework.TestCase; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.annotationsToTypes; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertAnnotationsMatch; +import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.set; + +public class ParameterTest extends TestCase { + private static class Type { + @AnnotationB + @AnnotationC + public void method(String parameter1, String parameter2) {} + + @AnnotationB + @AnnotationC + public void parameters(@AnnotationB @AnnotationD String parameter1, + @AnnotationC @AnnotationD String parameter2) {} + } + + public void testParameterAnnotations() throws Exception { + Method method = Type.class.getMethod("method", String.class, String.class); + Annotation[][] noParameterAnnotations = method.getParameterAnnotations(); + assertEquals(2, noParameterAnnotations.length); + assertEquals(set(), annotationsToTypes(noParameterAnnotations[0])); + assertEquals(set(), annotationsToTypes(noParameterAnnotations[1])); + + Method parameters = Type.class.getMethod("parameters", String.class, String.class); + Annotation[][] parameterAnnotations = parameters.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 AnnotatedClass { + public void singleAnnotation(@Repeated(1) String p0) {} + + public void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {} + + public void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {} + + public void multipleAnnotationOddity( + @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {} + + public void noAnnotation(String p0) {} + } + + public void testGetParameterAnnotations() throws Exception { + Class<?> c = AnnotatedClass.class; + + assertParameter0Annotations(c, "noAnnotation", EXPECT_EMPTY); + assertParameter0Annotations(c, "multipleAnnotationOddity", + "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})"); + assertParameter0Annotations(c, "multipleAnnotationExplicitSingle", + "@Container({@Repeated(1)})"); + assertParameter0Annotations(c, "multipleAnnotation", + "@Container({@Repeated(1), @Repeated(2)})"); + assertParameter0Annotations(c, "singleAnnotation", + "@Repeated(1)"); + } + + private static void assertParameter0Annotations( + Class<?> c, String methodName, String... expectedAnnotationStrings) throws Exception { + Annotation[][] allAnnotations = + c.getDeclaredMethod(methodName, String.class).getParameterAnnotations(); + final int expectedParameterCount = 1; + assertEquals(expectedParameterCount, allAnnotations.length); + + Annotation[] p0Annotations = allAnnotations[0]; + assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings); + } +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/MultipleAnnotation.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/MultipleAnnotation.java new file mode 100644 index 0000000000..d3e77ae479 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/MultipleAnnotation.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package libcore.java.lang.reflect.annotations.multipleannotation; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class MultipleAnnotation { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/package-info.java new file mode 100644 index 0000000000..1ab457ecf7 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotation/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Repeated(1) +@Repeated(2) +package libcore.java.lang.reflect.annotations.multipleannotation; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/MultipleAnnotationExplicitSingle.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/MultipleAnnotationExplicitSingle.java new file mode 100644 index 0000000000..d14ff198b2 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/MultipleAnnotationExplicitSingle.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.multipleannotationexplicitsingle; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class MultipleAnnotationExplicitSingle { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/package-info.java new file mode 100644 index 0000000000..cf41d87bbb --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationexplicitsingle/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Container({@Repeated(1)}) +package libcore.java.lang.reflect.annotations.multipleannotationexplicitsingle; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
\ No newline at end of file diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/MultipleAnnotationOddity.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/MultipleAnnotationOddity.java new file mode 100644 index 0000000000..b85f50ff8a --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/MultipleAnnotationOddity.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.multipleannotationoddity; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class MultipleAnnotationOddity { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/package-info.java new file mode 100644 index 0000000000..afbd99eda8 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/multipleannotationoddity/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Repeated(1) +@Container({@Repeated(2), @Repeated(3)}) +package libcore.java.lang.reflect.annotations.multipleannotationoddity; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container; +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
\ No newline at end of file diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/NoAnnotation.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/NoAnnotation.java new file mode 100644 index 0000000000..e7fd957565 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/NoAnnotation.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.noannotation; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class NoAnnotation { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/package-info.java index 1a84c2ef91..2942f1a740 100644 --- a/luni/src/test/java/libcore/java/lang/reflect/package-info.java +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/noannotation/package-info.java @@ -14,7 +14,7 @@ * limitations under the License. */ -//Used by AnnotationsTest. -@AnnotationsTest.RepeatableAnnotation -@AnnotationsTest.RepeatableAnnotation -package libcore.java.lang.reflect;
\ No newline at end of file +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +package libcore.java.lang.reflect.annotations.noannotation;
\ No newline at end of file diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/SingleAnnotation.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/SingleAnnotation.java new file mode 100644 index 0000000000..453b2996e5 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/SingleAnnotation.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.lang.reflect.annotations.singleannotation; + +import libcore.java.lang.reflect.annotations.PackageTest; + +/** + * This class exists so that (after it is loaded) the ClassLoader will be aware of the associated + * package and return a {@link Package} object. See {@link PackageTest}. + */ +public class SingleAnnotation { +} diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/package-info.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/package-info.java new file mode 100644 index 0000000000..3686f80799 --- /dev/null +++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/singleannotation/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See {@link libcore.java.lang.reflect.annotations.PackageTest}. + */ +@Repeated(1) +package libcore.java.lang.reflect.annotations.singleannotation; + +import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated; + |