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
17package libcore.java.lang.reflect;
18
19import java.lang.reflect.Constructor;
20import java.lang.reflect.Field;
21import java.lang.reflect.Method;
22import java.lang.reflect.ParameterizedType;
23import java.lang.reflect.Type;
24import java.lang.reflect.TypeVariable;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.List;
28import java.util.concurrent.Callable;
29import junit.framework.TestCase;
30import tests.util.ClassLoaderBuilder;
31
32/**
33 * This class creates another class loader to load multiple copies of various
34 * classes into the VM at once. Then it verifies that reflection resolves the
35 * class names using the correct class loader.
36 */
37public final class ClassLoaderReflectionTest extends TestCase {
38
39    /*
40     * Each of these class instances points to a different copy of the class
41     * than the one in the application class loader!
42     */
43    private Class<?> aClass;
44    private Class<?> aListClass;
45    private Class<?> bClass;
46    private Class<?> bStringClass;
47    private Class<?> cClass;
48    private Class<?> dClass;
49    private Class<?> eClass;
50    private Class<?> fClass;
51
52    @Override protected void setUp() throws Exception {
53        String prefix = ClassLoaderReflectionTest.class.getName();
54        ClassLoader loader = new ClassLoaderBuilder().withPrivateCopy(prefix).build();
55        aClass = loader.loadClass(prefix + "$A");
56        bClass = loader.loadClass(prefix + "$B");
57        cClass = loader.loadClass(prefix + "$C");
58        dClass = loader.loadClass(prefix + "$D");
59        eClass = loader.loadClass(prefix + "$E");
60        fClass = loader.loadClass(prefix + "$F");
61        aListClass = loader.loadClass(prefix + "$AList");
62        bStringClass = loader.loadClass(prefix + "$BString");
63    }
64
65    public void testLoadOneClassInTwoClassLoadersSimultaneously() throws Exception {
66        assertEquals(aClass.getName(), A.class.getName());
67        assertNotSame(aClass, A.class);
68    }
69
70    public void testField() throws Exception {
71        assertEquals(aClass, aListClass.getDeclaredField("field").getType());
72    }
73
74    /**
75     * http://code.google.com/p/android/issues/detail?id=10111
76     */
77    public void testGenericSuperclassParameter() throws Exception {
78        assertParameterizedType(aListClass.getGenericSuperclass(), ArrayList.class, aClass);
79    }
80
81    public void testGenericSuperclassRawType() throws Exception {
82        assertParameterizedType(bStringClass.getGenericSuperclass(), bClass, String.class);
83    }
84
85    public void testTypeParameters() throws Exception {
86        TypeVariable<? extends Class<?>>[] typeVariables = cClass.getTypeParameters();
87        assertEquals(2, typeVariables.length);
88        assertTypeVariable(typeVariables[0], "K", String.class);
89        assertTypeVariable(typeVariables[1], "V", aClass);
90    }
91
92    public void testGenericInterfaces() throws Exception {
93        Type[] types = eClass.getGenericInterfaces();
94        assertEquals(2, types.length);
95        // TODO: this test incorrectly assumes that interfaces will be returned in source order!
96        assertParameterizedType(types[0], Callable.class, aClass);
97        assertParameterizedType(types[1], dClass, aClass);
98    }
99
100    public void testFieldGenericType() throws Exception {
101        Field bString = fClass.getDeclaredField("bString");
102        assertParameterizedType(bString.getGenericType(), bClass, String.class);
103        Field listA = fClass.getDeclaredField("listA");
104        assertParameterizedType(listA.getGenericType(), List.class, aClass);
105    }
106
107    public void testConstructorGenericType() throws Exception {
108        Constructor<?> constructor = fClass.getDeclaredConstructors()[0];
109        Type[] parameters = constructor.getGenericParameterTypes();
110        assertParameterizedType(parameters[0], bClass, String.class);
111        assertParameterizedType(parameters[1], List.class, aClass);
112    }
113
114    public void testMethodGenericReturnType() throws Exception {
115        Method method = fClass.getDeclaredMethod("method", bClass, List.class);
116        assertParameterizedType(method.getGenericReturnType(), bClass, String.class);
117    }
118
119    public void testMethodGenericParameterTypes() throws Exception {
120        Method method = fClass.getDeclaredMethod("method", bClass, List.class);
121        Type[] types = method.getGenericParameterTypes();
122        assertEquals(2, types.length);
123        assertParameterizedType(types[0], bClass, String.class);
124        assertParameterizedType(types[1], List.class, aClass);
125    }
126
127    static class A {}
128    static class B<T> {
129        T field;
130    }
131    static class C<K extends String, V extends A> {}
132    interface D<T> {}
133    class E implements Callable<A>, D<A> {
134        public A call() throws Exception {
135            return null;
136        }
137    }
138    class F {
139        B<String> bString;
140        List<A> listA;
141        F(B<String> parameter, List<A> anotherParameter) {}
142        B<String> method(B<String> parameter, List<A> anotherParameter) {
143            return null;
144        }
145    }
146    static class AList extends ArrayList<A> {
147        A field;
148    }
149    static class BString extends B<String> {}
150
151    private void assertParameterizedType(Type actual, Type raw, Type... args) {
152        assertTrue(actual.toString(), actual instanceof ParameterizedType);
153        ParameterizedType parameterizedType = (ParameterizedType) actual;
154        assertEquals(raw, parameterizedType.getRawType());
155        assertEquals(Arrays.<Type>asList(args),
156                Arrays.asList(parameterizedType.getActualTypeArguments()));
157    }
158
159    private void assertTypeVariable(TypeVariable actual, String name, Type... bounds) {
160        assertEquals(name, actual.getName());
161        assertEquals(Arrays.<Type>asList(bounds), Arrays.asList(actual.getBounds()));
162    }
163}
164