Home | History | Annotate | Download | only in reflect
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.lang.reflect;
     18 
     19 import java.io.Serializable;
     20 import java.lang.reflect.Constructor;
     21 import java.lang.reflect.Field;
     22 import java.lang.reflect.Member;
     23 import java.lang.reflect.Method;
     24 import java.lang.reflect.ParameterizedType;
     25 import java.lang.reflect.Type;
     26 import java.lang.reflect.TypeVariable;
     27 import java.util.AbstractCollection;
     28 import java.util.AbstractList;
     29 import java.util.ArrayList;
     30 import java.util.List;
     31 import java.util.Map;
     32 import java.util.RandomAccess;
     33 import java.util.Set;
     34 import junit.framework.Assert;
     35 import junit.framework.TestCase;
     36 
     37 public final class ReflectionTest extends TestCase {
     38     String classA = "libcore.java.lang.reflect.ReflectionTest$A";
     39     String classB = "libcore.java.lang.reflect.ReflectionTest$B";
     40     String classC = "libcore.java.lang.reflect.ReflectionTest$C";
     41 
     42     public void testClassGetSuperclass() {
     43         assertEquals(AbstractList.class, ArrayList.class.getSuperclass());
     44         assertEquals(AbstractCollection.class, AbstractList.class.getSuperclass());
     45         assertEquals(AbstractCollection.class, AbstractList.class.getSuperclass());
     46         assertEquals(Object.class, AbstractCollection.class.getSuperclass());
     47         assertNull(Object.class.getSuperclass());
     48     }
     49 
     50     public void testPrimitiveGetSuperclass() {
     51         assertNull(boolean.class.getSuperclass());
     52         assertNull(int.class.getSuperclass());
     53         assertNull(double.class.getSuperclass());
     54         assertNull(void.class.getSuperclass());
     55     }
     56 
     57     public void testInterfaceGetSuperclass() {
     58         assertNull(Comparable.class.getSuperclass());
     59         assertNull(DefinesMember.class.getSuperclass());
     60         assertNull(ExtendsDefinesMember.class.getSuperclass());
     61     }
     62 
     63     /**
     64      * http://code.google.com/p/android/issues/detail?id=6636
     65      */
     66     public void testGenericSuperclassToString() throws Exception {
     67         assertEquals("java.util.ArrayList<" + classA + ">",
     68                 AList.class.getGenericSuperclass().toString());
     69     }
     70 
     71     public void testClassGetName() {
     72         assertEquals("int", int.class.getName());
     73         assertEquals("[I", int[].class.getName());
     74         assertEquals("java.lang.String", String.class.getName());
     75         assertEquals("[Ljava.lang.String;", String[].class.getName());
     76         assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getName());
     77         assertEquals(getClass().getName() + "$A", A.class.getName());
     78         assertEquals(getClass().getName() + "$B", B.class.getName());
     79         assertEquals(getClass().getName() + "$DefinesMember", DefinesMember.class.getName());
     80     }
     81 
     82     public void testClassGetCanonicalName() {
     83         assertEquals("int", int.class.getCanonicalName());
     84         assertEquals("int[]", int[].class.getCanonicalName());
     85         assertEquals("java.lang.String", String.class.getCanonicalName());
     86         assertEquals("java.lang.String[]", String[].class.getCanonicalName());
     87         assertEquals("libcore.java.lang.reflect.ReflectionTest", getClass().getCanonicalName());
     88         assertEquals(getClass().getName() + ".A", A.class.getCanonicalName());
     89         assertEquals(getClass().getName() + ".B", B.class.getCanonicalName());
     90         assertEquals(getClass().getName() + ".DefinesMember",
     91                 DefinesMember.class.getCanonicalName());
     92     }
     93 
     94     public void testFieldToString() throws Exception {
     95         Field fieldOne = C.class.getDeclaredField("fieldOne");
     96         String fieldOneRaw = "public static " + classA + " " + classC + ".fieldOne";
     97         assertEquals(fieldOneRaw, fieldOne.toString());
     98         assertEquals(fieldOneRaw, fieldOne.toGenericString());
     99 
    100         Field fieldTwo = C.class.getDeclaredField("fieldTwo");
    101         assertEquals("private transient volatile java.util.Map " + classC + ".fieldTwo",
    102                 fieldTwo.toString());
    103         assertEquals("private transient volatile java.util.Map<" + classA + ", java.lang.String> "
    104                 + classC + ".fieldTwo", fieldTwo.toGenericString());
    105 
    106         Field fieldThree = C.class.getDeclaredField("fieldThree");
    107         String fieldThreeRaw = "protected java.lang.Object[] " + classC + ".fieldThree";
    108         assertEquals(fieldThreeRaw, fieldThree.toString());
    109         String fieldThreeGeneric = "protected K[] " + classC + ".fieldThree";
    110         assertEquals(fieldThreeGeneric, fieldThree.toGenericString());
    111 
    112         Field fieldFour = C.class.getDeclaredField("fieldFour");
    113         String fieldFourRaw = "java.util.Map " + classC + ".fieldFour";
    114         assertEquals(fieldFourRaw, fieldFour.toString());
    115         String fieldFourGeneric = "java.util.Map<? super java.lang.Integer, java.lang.Integer[]> "
    116                 + classC + ".fieldFour";
    117         assertEquals(fieldFourGeneric, fieldFour.toGenericString());
    118 
    119         Field fieldFive = C.class.getDeclaredField("fieldFive");
    120         String fieldFiveRaw = "java.lang.String[][][][][] " + classC + ".fieldFive";
    121         assertEquals(fieldFiveRaw, fieldFive.toString());
    122         assertEquals(fieldFiveRaw, fieldFive.toGenericString());
    123     }
    124 
    125     public void testConstructorToString() throws Exception {
    126         Constructor constructorOne = C.class.getDeclaredConstructor(A.class);
    127         String constructorOneRaw = classC + "(" + classA + ") throws " + classB;
    128         assertEquals(constructorOneRaw, constructorOne.toString());
    129         assertEquals(constructorOneRaw, constructorOne.toGenericString());
    130 
    131         Constructor constructorTwo = C.class.getDeclaredConstructor(Map.class, Object.class);
    132         String constructorTwoRaw = "protected " + classC + "(java.util.Map,java.lang.Object)";
    133         assertEquals(constructorTwoRaw, constructorTwo.toString());
    134         String constructorTwoGeneric = "protected <T1> " + classC
    135                 + "(java.util.Map<? super " + classA + ", T1>,K)";
    136         assertEquals(constructorTwoGeneric, constructorTwo.toGenericString());
    137     }
    138 
    139     public void testMethodToString() throws Exception {
    140         Method methodOne = C.class.getDeclaredMethod("methodOne", A.class, C.class);
    141         String methodOneRaw = "protected final synchronized " + classA + " "
    142                 + classC + ".methodOne(" + classA + "," + classC + ") throws " + classB;
    143         assertEquals(methodOneRaw, methodOne.toString());
    144         assertEquals(methodOneRaw, methodOne.toGenericString());
    145 
    146         Method methodTwo = C.class.getDeclaredMethod("methodTwo", List.class);
    147         String methodTwoRaw = "public abstract java.util.Map "
    148                 + classC + ".methodTwo(java.util.List)";
    149         assertEquals(methodTwoRaw, methodTwo.toString());
    150         String methodTwoGeneric = "public abstract java.util.Map<" + classA + ", java.lang.String> "
    151                 + classC + ".methodTwo(java.util.List<" + classA + ">)";
    152         assertEquals(methodTwoGeneric, methodTwo.toGenericString());
    153 
    154         Method methodThree = C.class.getDeclaredMethod("methodThree", A.class, Set.class);
    155         String methodThreeRaw = "private static java.util.Map "
    156                 + classC + ".methodThree(" + classA + ",java.util.Set)";
    157         assertEquals(methodThreeRaw, methodThree.toString());
    158         String methodThreeGeneric = "private static <T1,T2> java.util.Map<T1, ?> "
    159                 + classC + ".methodThree(T1,java.util.Set<? super T2>)";
    160         assertEquals(methodThreeGeneric, methodThree.toGenericString());
    161 
    162         Method methodFour = C.class.getDeclaredMethod("methodFour", Set.class);
    163         String methodFourRaw = "public java.lang.Comparable " + classC + ".methodFour(java.util.Set)";
    164         assertEquals(methodFourRaw, methodFour.toString());
    165         String methodFourGeneric = "public <T> T " + classC + ".methodFour(java.util.Set<T>)";
    166         assertEquals(methodFourGeneric, methodFour.toGenericString());
    167     }
    168 
    169     public void testTypeVariableWithMultipleBounds() throws Exception {
    170         TypeVariable t = C.class.getDeclaredMethod("methodFour", Set.class).getTypeParameters()[0];
    171         assertEquals("T", t.toString());
    172 
    173         Type[] bounds = t.getBounds();
    174         ParameterizedType comparableT = (ParameterizedType) bounds[0];
    175         assertEquals(Comparable.class, comparableT.getRawType());
    176         assertEquals("T", ((TypeVariable) comparableT.getActualTypeArguments()[0]).getName());
    177         assertEquals(3, bounds.length);
    178         assertEquals(Serializable.class, bounds[1]);
    179         assertEquals(RandomAccess.class, bounds[2]);
    180     }
    181 
    182     public void testGetFieldNotFound() throws Exception {
    183         try {
    184             D.class.getField("noField");
    185             fail();
    186         } catch (NoSuchFieldException expected) {
    187         }
    188     }
    189 
    190     public void testGetDeclaredFieldNotFound() throws Exception {
    191         try {
    192             D.class.getDeclaredField("noField");
    193             fail();
    194         } catch (NoSuchFieldException expected) {
    195         }
    196     }
    197 
    198     public void testGetFieldNull() throws Exception {
    199         try {
    200             D.class.getField(null);
    201             fail();
    202         } catch (NullPointerException expected) {
    203         }
    204     }
    205 
    206     public void testGetDeclaredFieldNull() throws Exception {
    207         try {
    208             D.class.getDeclaredField(null);
    209             fail();
    210         } catch (NullPointerException expected) {
    211         }
    212     }
    213 
    214     public void testGetFieldIsRecursive() throws Exception {
    215         Field field = D.class.getField("fieldOne");
    216         assertEquals(C.class, field.getDeclaringClass());
    217     }
    218 
    219     public void testGetDeclaredFieldIsNotRecursive() {
    220         try {
    221             D.class.getDeclaredField("fieldOne");
    222             fail();
    223         } catch (NoSuchFieldException expected) {
    224         }
    225     }
    226 
    227     public void testGetFieldIsPublicOnly() throws Exception {
    228         C.class.getField("fieldOne"); // public
    229         try {
    230             C.class.getField("fieldTwo"); // private
    231             fail();
    232         } catch (NoSuchFieldException expected) {
    233         }
    234         try {
    235             C.class.getField("fieldThree"); // protected
    236             fail();
    237         } catch (NoSuchFieldException expected) {
    238         }
    239         try {
    240             C.class.getField("fieldFour"); // package-private
    241             fail();
    242         } catch (NoSuchFieldException expected) {
    243         }
    244     }
    245 
    246     public void testGetDeclaredFieldIsAllVisibilities() throws Exception {
    247         C.class.getDeclaredField("fieldOne"); // public
    248         C.class.getDeclaredField("fieldTwo"); // private
    249         C.class.getDeclaredField("fieldThree"); // protected
    250         C.class.getDeclaredField("fieldFour"); // package-private
    251     }
    252 
    253     public void testGetFieldViaExtendsThenImplements() throws Exception {
    254         Field field = ExtendsImplementsDefinesMember.class.getField("field");
    255         assertEquals(DefinesMember.class, field.getDeclaringClass());
    256     }
    257 
    258     public void testGetFieldViaImplementsThenExtends() throws Exception {
    259         Field field = ImplementsExtendsDefinesMember.class.getField("field");
    260         assertEquals(DefinesMember.class, field.getDeclaringClass());
    261     }
    262 
    263     public void testGetFieldsViaExtendsThenImplements() throws Exception {
    264         Field[] fields = ExtendsImplementsDefinesMember.class.getFields();
    265         assertTrue(names(fields).contains("field"));
    266     }
    267 
    268     public void testGetFieldsViaImplementsThenExtends() throws Exception {
    269         Field[] fields = ImplementsExtendsDefinesMember.class.getFields();
    270         assertTrue(names(fields).contains("field"));
    271     }
    272 
    273     public void testGetMethodViaExtendsThenImplements() throws Exception {
    274         Method method = ExtendsImplementsDefinesMember.class.getMethod("method");
    275         assertEquals(DefinesMember.class, method.getDeclaringClass());
    276     }
    277 
    278     public void testGetMethodViaImplementsThenExtends() throws Exception {
    279         Method method = ImplementsExtendsDefinesMember.class.getMethod("method");
    280         assertEquals(DefinesMember.class, method.getDeclaringClass());
    281     }
    282 
    283     public void testGetMethodsViaExtendsThenImplements() throws Exception {
    284         Method[] methods = ExtendsImplementsDefinesMember.class.getMethods();
    285         assertTrue(names(methods).contains("method"));
    286     }
    287 
    288     public void testGetMethodsViaImplementsThenExtends() throws Exception {
    289         Method[] methods = ImplementsExtendsDefinesMember.class.getMethods();
    290         assertTrue(names(methods).contains("method"));
    291     }
    292 
    293     public void testGetMethodsContainsNoDuplicates() throws Exception {
    294         Method[] methods = ExtendsAndImplementsDefinesMember.class.getMethods();
    295         assertEquals(1, count(names(methods), "method"));
    296     }
    297 
    298     public void testGetFieldsContainsNoDuplicates() throws Exception {
    299         Field[] fields = ExtendsAndImplementsDefinesMember.class.getFields();
    300         assertEquals(1, count(names(fields), "field"));
    301     }
    302 
    303     public void testIsLocalClass() {
    304         A methodLevelAnonymous = new A() {};
    305         class Local {}
    306         class $Local$1 {}
    307         assertFalse(ReflectionTest.class.isLocalClass());
    308         assertFalse(A.class.isLocalClass());
    309         assertFalse($Dollar$1.class.isLocalClass());
    310         assertFalse(CLASS_LEVEL_ANONYMOUS.getClass().isLocalClass());
    311         assertFalse(methodLevelAnonymous.getClass().isLocalClass());
    312         assertTrue(Local.class.isLocalClass());
    313         assertTrue($Local$1.class.isLocalClass());
    314         assertFalse(int.class.isLocalClass());
    315         assertFalse(Object.class.isLocalClass());
    316     }
    317 
    318     public void testIsAnonymousClass() {
    319         A methodLevelAnonymous = new A() {};
    320         class Local {}
    321         class $Local$1 {}
    322         assertFalse(ReflectionTest.class.isAnonymousClass());
    323         assertFalse(A.class.isAnonymousClass());
    324         assertFalse($Dollar$1.class.isAnonymousClass());
    325         assertTrue(CLASS_LEVEL_ANONYMOUS.getClass().isAnonymousClass());
    326         assertTrue(methodLevelAnonymous.getClass().isAnonymousClass());
    327         assertFalse(Local.class.isAnonymousClass());
    328         assertFalse($Local$1.class.isAnonymousClass());
    329         assertFalse(int.class.isAnonymousClass());
    330         assertFalse(Object.class.isAnonymousClass());
    331     }
    332 
    333     /**
    334      * Class.isEnum() erroneously returned true for indirect descendants of
    335      * Enum. http://b/1062200.
    336      */
    337     public void testClassIsEnum() {
    338         Class<?> trafficClass = TrafficLights.class;
    339         Class<?> redClass = TrafficLights.RED.getClass();
    340         Class<?> yellowClass = TrafficLights.YELLOW.getClass();
    341         Class<?> greenClass = TrafficLights.GREEN.getClass();
    342         assertSame(trafficClass, redClass);
    343         assertNotSame(trafficClass, yellowClass);
    344         assertNotSame(trafficClass, greenClass);
    345         assertNotSame(yellowClass, greenClass);
    346         assertTrue(trafficClass.isEnum());
    347         assertTrue(redClass.isEnum());
    348         assertFalse(yellowClass.isEnum());
    349         assertFalse(greenClass.isEnum());
    350         assertNotNull(trafficClass.getEnumConstants());
    351         assertNull(yellowClass.getEnumConstants());
    352         assertNull(greenClass.getEnumConstants());
    353     }
    354 
    355     static class $Dollar$1 {}
    356     static class A {}
    357     static class AList extends ArrayList<A> {}
    358     static A CLASS_LEVEL_ANONYMOUS = new A() {};
    359 
    360     static class B extends Exception {}
    361 
    362     public static abstract class C<K> {
    363         public static A fieldOne;
    364         private transient volatile Map<A, String> fieldTwo;
    365         protected K[] fieldThree;
    366         Map<? super Integer, Integer[]> fieldFour;
    367         String[][][][][] fieldFive;
    368 
    369         C(A a) throws B {}
    370         protected <T1 extends A> C(Map<? super A, T1> a, K s) {}
    371 
    372         protected final synchronized A methodOne(A parameterOne, C parameterTwo) throws B {
    373             return null;
    374         }
    375         public abstract Map<A, String> methodTwo(List<A> onlyParameter);
    376         @Deprecated /** this annotation is used because it has runtime retention */
    377         private static <T1 extends A, T2> Map<T1, ?> methodThree(T1 t, Set<? super T2> t2s) {
    378             return null;
    379         }
    380         public <T extends Comparable<T> & Serializable & RandomAccess> T methodFour(Set<T> t) {
    381             return null;
    382         }
    383     }
    384 
    385     public static class D extends C<String> {
    386         public D(A a) throws B {
    387             super(a);
    388         }
    389         @Override public Map<A, String> methodTwo(List<A> onlyParameter) {
    390             return null;
    391         }
    392     }
    393 
    394     interface DefinesMember {
    395         String field = "s";
    396         void method();
    397     }
    398     static abstract class ImplementsDefinesMember implements DefinesMember {}
    399     static abstract class ExtendsImplementsDefinesMember extends ImplementsDefinesMember {}
    400     interface ExtendsDefinesMember extends DefinesMember {}
    401     static abstract class ImplementsExtendsDefinesMember implements ExtendsDefinesMember {}
    402     static abstract class ExtendsAndImplementsDefinesMember extends ImplementsDefinesMember
    403             implements DefinesMember {}
    404 
    405     private List<String> names(Member[] methods) {
    406         List<String> result = new ArrayList<String>();
    407         for (Member method : methods) {
    408             result.add(method.getName());
    409         }
    410         return result;
    411     }
    412 
    413     private int count(List<?> list, Object element) {
    414         int result = 0;
    415         for (Object o : list) {
    416             if (o.equals(element)) {
    417                 result++;
    418             }
    419         }
    420         return result;
    421     }
    422 
    423     enum TrafficLights {
    424         RED,
    425         YELLOW {},
    426         GREEN {
    427             @SuppressWarnings("unused")
    428             int i;
    429             @SuppressWarnings("unused")
    430             void foobar() {}
    431         }
    432     }
    433 }
    434