| /* |
| * Copyright (C) 2010 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; |
| |
| import java.io.Serializable; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Member; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.lang.reflect.TypeVariable; |
| import java.util.ArrayList; |
| 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 { |
| String classA = "libcore.java.lang.reflect.ReflectionTest$A"; |
| String classB = "libcore.java.lang.reflect.ReflectionTest$B"; |
| String classC = "libcore.java.lang.reflect.ReflectionTest$C"; |
| |
| /** |
| * http://code.google.com/p/android/issues/detail?id=6636 |
| */ |
| public void testGenericSuperclassToString() throws Exception { |
| assertEquals("java.util.ArrayList<" + classA + ">", |
| AList.class.getGenericSuperclass().toString()); |
| } |
| |
| public void testClassGetName() { |
| assertEquals("int", int.class.getName()); |
| assertEquals("[I", int[].class.getName()); |
| assertEquals("java.lang.String", String.class.getName()); |
| assertEquals("[Ljava.lang.String;", String[].class.getName()); |
| assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getName()); |
| assertEquals(getClass().getName() + "$A", A.class.getName()); |
| assertEquals(getClass().getName() + "$B", B.class.getName()); |
| assertEquals(getClass().getName() + "$DefinesMember", DefinesMember.class.getName()); |
| } |
| |
| public void testClassGetCanonicalName() { |
| assertEquals("int", int.class.getCanonicalName()); |
| assertEquals("int[]", int[].class.getCanonicalName()); |
| assertEquals("java.lang.String", String.class.getCanonicalName()); |
| assertEquals("java.lang.String[]", String[].class.getCanonicalName()); |
| assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getCanonicalName()); |
| assertEquals(getClass().getName() + ".A", A.class.getCanonicalName()); |
| assertEquals(getClass().getName() + ".B", B.class.getCanonicalName()); |
| assertEquals(getClass().getName() + ".DefinesMember", |
| DefinesMember.class.getCanonicalName()); |
| } |
| |
| public void testFieldToString() throws Exception { |
| Field fieldOne = C.class.getDeclaredField("fieldOne"); |
| String fieldOneRaw = "public static " + classA + " " + classC + ".fieldOne"; |
| assertEquals(fieldOneRaw, fieldOne.toString()); |
| assertEquals(fieldOneRaw, fieldOne.toGenericString()); |
| |
| Field fieldTwo = C.class.getDeclaredField("fieldTwo"); |
| assertEquals("private transient volatile java.util.Map " + classC + ".fieldTwo", |
| fieldTwo.toString()); |
| assertEquals("private transient volatile java.util.Map<" + classA + ", java.lang.String> " |
| + classC + ".fieldTwo", fieldTwo.toGenericString()); |
| |
| Field fieldThree = C.class.getDeclaredField("fieldThree"); |
| String fieldThreeRaw = "protected java.lang.Object[] " + classC + ".fieldThree"; |
| assertEquals(fieldThreeRaw, fieldThree.toString()); |
| String fieldThreeGeneric = "protected K[] " + classC + ".fieldThree"; |
| assertEquals(fieldThreeGeneric, fieldThree.toGenericString()); |
| |
| Field fieldFour = C.class.getDeclaredField("fieldFour"); |
| String fieldFourRaw = "java.util.Map " + classC + ".fieldFour"; |
| assertEquals(fieldFourRaw, fieldFour.toString()); |
| String fieldFourGeneric = "java.util.Map<? super java.lang.Integer, java.lang.Integer[]> " |
| + classC + ".fieldFour"; |
| assertEquals(fieldFourGeneric, fieldFour.toGenericString()); |
| |
| Field fieldFive = C.class.getDeclaredField("fieldFive"); |
| String fieldFiveRaw = "java.lang.String[][][][][] " + classC + ".fieldFive"; |
| assertEquals(fieldFiveRaw, fieldFive.toString()); |
| assertEquals(fieldFiveRaw, fieldFive.toGenericString()); |
| } |
| |
| public void testConstructorToString() throws Exception { |
| Constructor constructorOne = C.class.getDeclaredConstructor(A.class); |
| String constructorOneRaw = classC + "(" + classA + ") throws " + classB; |
| assertEquals(constructorOneRaw, constructorOne.toString()); |
| assertEquals(constructorOneRaw, constructorOne.toGenericString()); |
| |
| Constructor constructorTwo = C.class.getDeclaredConstructor(Map.class, Object.class); |
| String constructorTwoRaw = "protected " + classC + "(java.util.Map,java.lang.Object)"; |
| assertEquals(constructorTwoRaw, constructorTwo.toString()); |
| String constructorTwoGeneric = "protected <T1> " + classC |
| + "(java.util.Map<? super " + classA + ", T1>,K)"; |
| assertEquals(constructorTwoGeneric, constructorTwo.toGenericString()); |
| } |
| |
| public void testMethodToString() throws Exception { |
| Method methodOne = C.class.getDeclaredMethod("methodOne", A.class, C.class); |
| String methodOneRaw = "protected final synchronized " + classA + " " |
| + classC + ".methodOne(" + classA + "," + classC + ") throws " + classB; |
| assertEquals(methodOneRaw, methodOne.toString()); |
| assertEquals(methodOneRaw, methodOne.toGenericString()); |
| |
| Method methodTwo = C.class.getDeclaredMethod("methodTwo", List.class); |
| String methodTwoRaw = "public abstract java.util.Map " |
| + classC + ".methodTwo(java.util.List)"; |
| assertEquals(methodTwoRaw, methodTwo.toString()); |
| String methodTwoGeneric = "public abstract java.util.Map<" + classA + ", java.lang.String> " |
| + classC + ".methodTwo(java.util.List<" + classA + ">)"; |
| assertEquals(methodTwoGeneric, methodTwo.toGenericString()); |
| |
| Method methodThree = C.class.getDeclaredMethod("methodThree", A.class, Set.class); |
| String methodThreeRaw = "private static java.util.Map " |
| + classC + ".methodThree(" + classA + ",java.util.Set)"; |
| assertEquals(methodThreeRaw, methodThree.toString()); |
| String methodThreeGeneric = "private static <T1,T2> java.util.Map<T1, ?> " |
| + classC + ".methodThree(T1,java.util.Set<? super T2>)"; |
| assertEquals(methodThreeGeneric, methodThree.toGenericString()); |
| |
| Method methodFour = C.class.getDeclaredMethod("methodFour", Set.class); |
| String methodFourRaw = "public java.lang.Comparable " + classC + ".methodFour(java.util.Set)"; |
| assertEquals(methodFourRaw, methodFour.toString()); |
| String methodFourGeneric = "public <T> T " + classC + ".methodFour(java.util.Set<T>)"; |
| assertEquals(methodFourGeneric, methodFour.toGenericString()); |
| } |
| |
| public void testTypeVariableWithMultipleBounds() throws Exception { |
| TypeVariable t = C.class.getDeclaredMethod("methodFour", Set.class).getTypeParameters()[0]; |
| assertEquals("T", t.toString()); |
| |
| Type[] bounds = t.getBounds(); |
| ParameterizedType comparableT = (ParameterizedType) bounds[0]; |
| assertEquals(Comparable.class, comparableT.getRawType()); |
| assertEquals("T", ((TypeVariable) comparableT.getActualTypeArguments()[0]).getName()); |
| assertEquals(3, bounds.length); |
| assertEquals(Serializable.class, bounds[1]); |
| assertEquals(RandomAccess.class, bounds[2]); |
| } |
| |
| public void testGetFieldNotFound() throws Exception { |
| try { |
| D.class.getField("noField"); |
| fail(); |
| } catch (NoSuchFieldException expected) { |
| } |
| } |
| |
| public void testGetDeclaredFieldNotFound() throws Exception { |
| try { |
| D.class.getDeclaredField("noField"); |
| fail(); |
| } catch (NoSuchFieldException expected) { |
| } |
| } |
| |
| public void testGetFieldNull() throws Exception { |
| try { |
| D.class.getField(null); |
| fail(); |
| } catch (NullPointerException expected) { |
| } |
| } |
| |
| public void testGetDeclaredFieldNull() throws Exception { |
| try { |
| D.class.getDeclaredField(null); |
| fail(); |
| } catch (NullPointerException expected) { |
| } |
| } |
| |
| public void testGetFieldIsRecursive() throws Exception { |
| Field field = D.class.getField("fieldOne"); |
| assertEquals(C.class, field.getDeclaringClass()); |
| } |
| |
| public void testGetDeclaredFieldIsNotRecursive() { |
| try { |
| D.class.getDeclaredField("fieldOne"); |
| fail(); |
| } catch (NoSuchFieldException expected) { |
| } |
| } |
| |
| public void testGetFieldIsPublicOnly() throws Exception { |
| C.class.getField("fieldOne"); // public |
| try { |
| C.class.getField("fieldTwo"); // private |
| fail(); |
| } catch (NoSuchFieldException expected) { |
| } |
| try { |
| C.class.getField("fieldThree"); // protected |
| fail(); |
| } catch (NoSuchFieldException expected) { |
| } |
| try { |
| C.class.getField("fieldFour"); // package-private |
| fail(); |
| } catch (NoSuchFieldException expected) { |
| } |
| } |
| |
| public void testGetDeclaredFieldIsAllVisibilities() throws Exception { |
| C.class.getDeclaredField("fieldOne"); // public |
| C.class.getDeclaredField("fieldTwo"); // private |
| C.class.getDeclaredField("fieldThree"); // protected |
| C.class.getDeclaredField("fieldFour"); // package-private |
| } |
| |
| public void testGetFieldViaExtendsThenImplements() throws Exception { |
| Field field = ExtendsImplementsDefinesMember.class.getField("field"); |
| assertEquals(DefinesMember.class, field.getDeclaringClass()); |
| } |
| |
| public void testGetFieldViaImplementsThenExtends() throws Exception { |
| Field field = ImplementsExtendsDefinesMember.class.getField("field"); |
| assertEquals(DefinesMember.class, field.getDeclaringClass()); |
| } |
| |
| public void testGetFieldsViaExtendsThenImplements() throws Exception { |
| Field[] fields = ExtendsImplementsDefinesMember.class.getFields(); |
| assertTrue(names(fields).contains("field")); |
| } |
| |
| public void testGetFieldsViaImplementsThenExtends() throws Exception { |
| Field[] fields = ImplementsExtendsDefinesMember.class.getFields(); |
| assertTrue(names(fields).contains("field")); |
| } |
| |
| public void testGetMethodViaExtendsThenImplements() throws Exception { |
| Method method = ExtendsImplementsDefinesMember.class.getMethod("method"); |
| assertEquals(DefinesMember.class, method.getDeclaringClass()); |
| } |
| |
| public void testGetMethodViaImplementsThenExtends() throws Exception { |
| Method method = ImplementsExtendsDefinesMember.class.getMethod("method"); |
| assertEquals(DefinesMember.class, method.getDeclaringClass()); |
| } |
| |
| public void testGetMethodsViaExtendsThenImplements() throws Exception { |
| Method[] methods = ExtendsImplementsDefinesMember.class.getMethods(); |
| assertTrue(names(methods).contains("method")); |
| } |
| |
| public void testGetMethodsViaImplementsThenExtends() throws Exception { |
| Method[] methods = ImplementsExtendsDefinesMember.class.getMethods(); |
| assertTrue(names(methods).contains("method")); |
| } |
| |
| public void testGetMethodsContainsNoDuplicates() throws Exception { |
| Method[] methods = ExtendsAndImplementsDefinesMember.class.getMethods(); |
| assertEquals(1, count(names(methods), "method")); |
| } |
| |
| public void testGetFieldsContainsNoDuplicates() throws Exception { |
| Field[] fields = ExtendsAndImplementsDefinesMember.class.getFields(); |
| assertEquals(1, count(names(fields), "field")); |
| } |
| |
| /** |
| * Class.isEnum() erroneously returned true for indirect descendants of |
| * Enum. http://b/1062200. |
| */ |
| public void testClassIsEnum() { |
| Class<?> trafficClass = TrafficLights.class; |
| Class<?> redClass = TrafficLights.RED.getClass(); |
| Class<?> yellowClass = TrafficLights.YELLOW.getClass(); |
| Class<?> greenClass = TrafficLights.GREEN.getClass(); |
| assertSame(trafficClass, redClass); |
| assertNotSame(trafficClass, yellowClass); |
| assertNotSame(trafficClass, greenClass); |
| assertNotSame(yellowClass, greenClass); |
| assertTrue(trafficClass.isEnum()); |
| assertTrue(redClass.isEnum()); |
| assertFalse(yellowClass.isEnum()); |
| assertFalse(greenClass.isEnum()); |
| assertNotNull(trafficClass.getEnumConstants()); |
| assertNull(yellowClass.getEnumConstants()); |
| assertNull(greenClass.getEnumConstants()); |
| } |
| |
| static class A {} |
| static class AList extends ArrayList<A> {} |
| |
| static class B extends Exception {} |
| |
| public static abstract class C<K> { |
| public static A fieldOne; |
| private transient volatile Map<A, String> fieldTwo; |
| protected K[] fieldThree; |
| Map<? super Integer, Integer[]> fieldFour; |
| String[][][][][] fieldFive; |
| |
| C(A a) throws B {} |
| protected <T1 extends A> C(Map<? super A, T1> a, K s) {} |
| |
| protected final synchronized A methodOne(A parameterOne, C parameterTwo) throws B { |
| return null; |
| } |
| public abstract Map<A, String> methodTwo(List<A> onlyParameter); |
| @Deprecated /** this annotation is used because it has runtime retention */ |
| private static <T1 extends A, T2> Map<T1, ?> methodThree(T1 t, Set<? super T2> t2s) { |
| return null; |
| } |
| public <T extends Comparable<T> & Serializable & RandomAccess> T methodFour(Set<T> t) { |
| return null; |
| } |
| } |
| |
| public static class D extends C<String> { |
| public D(A a) throws B { |
| super(a); |
| } |
| @Override public Map<A, String> methodTwo(List<A> onlyParameter) { |
| return null; |
| } |
| } |
| |
| interface DefinesMember { |
| String field = "s"; |
| void method(); |
| } |
| static abstract class ImplementsDefinesMember implements DefinesMember {} |
| static abstract class ExtendsImplementsDefinesMember extends ImplementsDefinesMember {} |
| interface ExtendsDefinesMember extends DefinesMember {} |
| static abstract class ImplementsExtendsDefinesMember implements ExtendsDefinesMember {} |
| static abstract class ExtendsAndImplementsDefinesMember extends ImplementsDefinesMember |
| implements DefinesMember {} |
| |
| private List<String> names(Member[] methods) { |
| List<String> result = new ArrayList<String>(); |
| for (Member method : methods) { |
| result.add(method.getName()); |
| } |
| return result; |
| } |
| |
| private int count(List<?> list, Object element) { |
| int result = 0; |
| for (Object o : list) { |
| if (o.equals(element)) { |
| result++; |
| } |
| } |
| return result; |
| } |
| |
| enum TrafficLights { |
| RED, |
| YELLOW {}, |
| GREEN { |
| @SuppressWarnings("unused") |
| int i; |
| @SuppressWarnings("unused") |
| void foobar() {} |
| } |
| } |
| } |