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