blob: cdce405b05e71c9871a8a6bc151f3e3d6664795f [file] [log] [blame]
/*
* 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() {}
}
}
}