summaryrefslogtreecommitdiffstats
path: root/luni
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2011-02-23 13:33:25 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-02-23 13:33:25 -0800
commit217766d68f160dd03def5d5f983d5330c24a3ed7 (patch)
tree853931b70c7d9e1e3855aaef9e599e8bbc87fbb7 /luni
parent482d294ebd5dff55f5397d5991f9f0e3808e5cac (diff)
parent11229f6af89fc54e70675fcab098b1572d6e539e (diff)
downloadlibcore-217766d68f160dd03def5d5f983d5330c24a3ed7.zip
libcore-217766d68f160dd03def5d5f983d5330c24a3ed7.tar.gz
libcore-217766d68f160dd03def5d5f983d5330c24a3ed7.tar.bz2
Merge "Optimize Class.getMethod() by loading only one method."
Diffstat (limited to 'luni')
-rw-r--r--luni/src/main/java/java/lang/Class.java150
-rw-r--r--luni/src/main/java/java/lang/ClassLoader.java8
-rw-r--r--luni/src/main/java/java/lang/ClassMembers.java126
-rw-r--r--luni/src/main/java/java/lang/Enum.java2
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java31
-rw-r--r--luni/src/test/java/libcore/java/lang/reflect/MethodTest.java97
6 files changed, 193 insertions, 221 deletions
diff --git a/luni/src/main/java/java/lang/Class.java b/luni/src/main/java/java/lang/Class.java
index ea29737..3058305 100644
--- a/luni/src/main/java/java/lang/Class.java
+++ b/luni/src/main/java/java/lang/Class.java
@@ -35,7 +35,7 @@ package java.lang;
import dalvik.system.VMStack;
import java.io.InputStream;
import java.io.Serializable;
-import static java.lang.ClassMembers.*;
+import static java.lang.ClassMembers.REFLECT;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.reflect.AccessibleObject;
@@ -262,7 +262,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* access.
*/
public Class<?>[] getClasses() {
- checkPublicMemberAccess();
return getFullListOfClasses(true);
}
@@ -457,8 +456,8 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
@SuppressWarnings("unchecked")
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException,
SecurityException {
- checkPublicMemberAccess();
- return getMatchingConstructor(getDeclaredConstructors(this, true), parameterTypes);
+ return (Constructor) ClassMembers.getConstructorOrMethod(
+ this, "<init>", false, true, parameterTypes);
}
/**
@@ -475,7 +474,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getDeclaredConstructors()
*/
public Constructor<?>[] getConstructors() throws SecurityException {
- checkPublicMemberAccess();
return getDeclaredConstructors(this, true);
}
@@ -505,7 +503,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* access.
*/
public Class<?>[] getDeclaredClasses() throws SecurityException {
- checkDeclaredMemberAccess();
return getDeclaredClasses(this, false);
}
@@ -564,8 +561,8 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
@SuppressWarnings("unchecked")
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
- checkDeclaredMemberAccess();
- return getMatchingConstructor(getDeclaredConstructors(this, false), parameterTypes);
+ return (Constructor) ClassMembers.getConstructorOrMethod(
+ this, "<init>", false, false, parameterTypes);
}
/**
@@ -583,7 +580,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getConstructors()
*/
public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
- checkDeclaredMemberAccess();
return getDeclaredConstructors(this, false);
}
@@ -597,42 +593,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
*/
private static native <T> Constructor<T>[] getDeclaredConstructors(Class<T> clazz, boolean publicOnly);
- /*
- * Finds a constructor with a given signature.
- *
- * @param list the list of constructors to search through
- * @param parameterTypes the formal parameter list
- * @return the matching constructor
- * @throws NoSuchMethodException if the constructor does not exist.
- */
- private Constructor<T> getMatchingConstructor(
- Constructor<T>[] constructors, Class<?>[] parameterTypes)
- throws NoSuchMethodException {
- for (Constructor<T> constructor : constructors) {
- if (compareClassLists(constructor.getParameterTypes(), parameterTypes)) {
- return constructor;
- }
- }
-
- // BEGIN android-changed
- StringBuilder sb = new StringBuilder();
- sb.append(getSimpleName());
- sb.append('(');
- boolean first = true;
- if (parameterTypes != null) {
- for (Class<?> p : parameterTypes) {
- if (!first) {
- sb.append(',');
- }
- first = false;
- sb.append(p.getSimpleName());
- }
- }
- sb.append(')');
- throw new NoSuchMethodException(sb.toString());
- // END android-changed
- }
-
/**
* Returns a {@code Field} object for the field with the specified name
* which is declared in the class represented by this {@code Class}.
@@ -648,8 +608,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getField(String)
*/
public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException {
- checkDeclaredMemberAccess();
-
Field[] fields = getClassMembers().getDeclaredFields();
Field field = findFieldByName(fields, name);
@@ -674,8 +632,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getFields()
*/
public Field[] getDeclaredFields() throws SecurityException {
- checkDeclaredMemberAccess();
-
// Return a copy of the private (to the package) array.
Field[] fields = getClassMembers().getDeclaredFields();
return ClassMembers.deepCopy(fields);
@@ -713,16 +669,12 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
*/
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
- checkDeclaredMemberAccess();
-
- Method[] methods = getClassMembers().getDeclaredMethods();
- Method method = findMethodByName(methods, name, parameterTypes);
-
- /*
- * Make a copy of the private (to the package) object, so that
- * setAccessible() won't alter the private instance.
- */
- return REFLECT.clone(method);
+ Member member = ClassMembers.getConstructorOrMethod(
+ this, name, false, false, parameterTypes);
+ if (member instanceof Constructor) {
+ throw new NoSuchMethodException(name);
+ }
+ return (Method) member;
}
/**
@@ -739,8 +691,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getMethods()
*/
public Method[] getDeclaredMethods() throws SecurityException {
- checkDeclaredMemberAccess();
-
// Return a copy of the private (to the package) array.
Method[] methods = getClassMembers().getDeclaredMethods();
return ClassMembers.deepCopy(methods);
@@ -753,6 +703,15 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
static native Method[] getDeclaredMethods(Class<?> clazz, boolean publicOnly);
/**
+ * Returns the constructor or method if it is defined by {@code clazz}; null
+ * otherwise. This may return a non-public member.
+ *
+ * @param name the method name, or "<init>" to get a constructor.
+ */
+ static native Member getDeclaredConstructorOrMethod(
+ Class clazz, String name, Class[] args);
+
+ /**
* Returns the {@link ClassMembers} for this instance.
*/
@SuppressWarnings("unchecked") // cache key and value types always agree
@@ -803,7 +762,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
@SuppressWarnings("unchecked")
public T[] getEnumConstants() {
if (isEnum()) {
- checkPublicMemberAccess();
T[] values = getClassMembers().getEnumValuesInOrder();
// Copy the private (to the package) array.
@@ -830,8 +788,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getDeclaredField(String)
*/
public Field getField(String name) throws NoSuchFieldException, SecurityException {
- checkPublicMemberAccess();
-
Field[] fields = getClassMembers().getAllPublicFields();
Field field = findFieldByName(fields, name);
@@ -880,8 +836,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getDeclaredFields()
*/
public Field[] getFields() throws SecurityException {
- checkPublicMemberAccess();
-
// Return a copy of the private (to the package) array.
Field[] fields = getClassMembers().getAllPublicFields();
return ClassMembers.deepCopy(fields);
@@ -925,7 +879,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
*/
public native Class<?>[] getInterfaces();
- // Changed to raw type to be closer to the RI
/**
* Returns a {@code Method} object which represents the public method with
* the specified name and parameter types. This method first searches the
@@ -948,16 +901,11 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
*/
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException,
SecurityException {
- checkPublicMemberAccess();
-
- Method[] methods = getClassMembers().getMethods();
- Method method = findMethodByName(methods, name, parameterTypes);
-
- /*
- * Make a copy of the private (to the package) object, so that
- * setAccessible() won't alter the private instance.
- */
- return REFLECT.clone(method);
+ Member member = ClassMembers.getConstructorOrMethod(this, name, true, true, parameterTypes);
+ if (member instanceof Constructor) {
+ throw new NoSuchMethodException(name);
+ }
+ return (Method) member;
}
/**
@@ -978,59 +926,12 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* @see #getDeclaredMethods()
*/
public Method[] getMethods() throws SecurityException {
- checkPublicMemberAccess();
-
// Return a copy of the private (to the package) array.
Method[] methods = getClassMembers().getMethods();
return ClassMembers.deepCopy(methods);
}
/**
- * Performs the security checks regarding the access of a public
- * member of this {@code Class}.
- *
- * <p><b>Note:</b> Because of the {@code getCallingClassLoader2()}
- * check, this method must be called exactly one level deep into a
- * public method on this instance.</p>
- */
- /*package*/ void checkPublicMemberAccess() {
- SecurityManager smgr = System.getSecurityManager();
-
- if (smgr != null) {
- smgr.checkMemberAccess(this, Member.PUBLIC);
-
- ClassLoader calling = VMStack.getCallingClassLoader2();
- ClassLoader current = getClassLoader();
-
- if (calling != null && !calling.isAncestorOf(current)) {
- smgr.checkPackageAccess(this.getPackage().getName());
- }
- }
- }
-
- /**
- * Performs the security checks regarding the access of a declared
- * member of this {@code Class}.
- *
- * <p><b>Note:</b> Because of the {@code getCallingClassLoader2()}
- * check, this method must be called exactly one level deep into a
- * public method on this instance.</p>
- */
- private void checkDeclaredMemberAccess() {
- SecurityManager smgr = System.getSecurityManager();
- if (smgr != null) {
- smgr.checkMemberAccess(this, Member.DECLARED);
-
- ClassLoader calling = VMStack.getCallingClassLoader2();
- ClassLoader current = getClassLoader();
-
- if (calling != null && !calling.isAncestorOf(current)) {
- smgr.checkPackageAccess(this.getPackage().getName());
- }
- }
- }
-
- /**
* Returns an integer that represents the modifiers of the class represented
* by this {@code Class}. The returned value is a combination of bits
* defined by constants in the {@link Modifier} class.
@@ -1397,7 +1298,6 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe
* new instances.
*/
public T newInstance() throws InstantiationException, IllegalAccessException {
- checkPublicMemberAccess();
return newInstanceImpl();
}
diff --git a/luni/src/main/java/java/lang/ClassLoader.java b/luni/src/main/java/java/lang/ClassLoader.java
index 43990cc..44a24f9 100644
--- a/luni/src/main/java/java/lang/ClassLoader.java
+++ b/luni/src/main/java/java/lang/ClassLoader.java
@@ -135,14 +135,6 @@ public abstract class ClassLoader {
* the system class loader.
*/
public static ClassLoader getSystemClassLoader() {
- SecurityManager smgr = System.getSecurityManager();
- if (smgr != null) {
- ClassLoader caller = VMStack.getCallingClassLoader();
- if (caller != null && !caller.isAncestorOf(SystemClassLoader.loader)) {
- smgr.checkPermission(new RuntimePermission("getClassLoader"));
- }
- }
-
return SystemClassLoader.loader;
}
diff --git a/luni/src/main/java/java/lang/ClassMembers.java b/luni/src/main/java/java/lang/ClassMembers.java
index 5660544..79eb1c3 100644
--- a/luni/src/main/java/java/lang/ClassMembers.java
+++ b/luni/src/main/java/java/lang/ClassMembers.java
@@ -19,7 +19,9 @@ package java.lang;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -28,6 +30,7 @@ import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import libcore.util.BasicLruCache;
+import libcore.util.EmptyArray;
import org.apache.harmony.kernel.vm.LangAccess;
import org.apache.harmony.kernel.vm.ReflectionAccess;
@@ -39,8 +42,6 @@ import org.apache.harmony.kernel.vm.ReflectionAccess;
* they should ever escape the package.
*/
/*package*/ class ClassMembers<T> {
- // TODO: Add constructors and fields.
-
static final BasicLruCache<Class<?>, ClassMembers<?>> cache
= new BasicLruCache<Class<?>, ClassMembers<?>>(16) {
@SuppressWarnings("unchecked") // use raw types since javac forbids "new ClassCache<?>(key)"
@@ -180,15 +181,9 @@ import org.apache.harmony.kernel.vm.ReflectionAccess;
/*
* Remove methods defined by multiple types, preferring to keep methods
* declared by derived types.
- *
- * Classes may define multiple methods with the same name and parameter
- * types due to covariant return types. In this case both are returned,
- * with the non-synthetic method first because it is preferred by
- * getMethod(String,Class[]).
*/
Collections.sort(allMethods, Method.ORDER_BY_SIGNATURE);
- List<Method> natural = new ArrayList<Method>(allMethods.size());
- List<Method> synthetic = new ArrayList<Method>(allMethods.size());
+ List<Method> result = new ArrayList<Method>(allMethods.size());
Method previous = null;
for (Method method : allMethods) {
if (previous != null
@@ -196,16 +191,9 @@ import org.apache.harmony.kernel.vm.ReflectionAccess;
&& method.getDeclaringClass() != previous.getDeclaringClass()) {
continue;
}
- if (method.isSynthetic()) {
- synthetic.add(method);
- } else {
- natural.add(method);
- }
+ result.add(method);
previous = method;
}
- List<Method> result = new ArrayList<Method>(allMethods.size());
- result.addAll(natural);
- result.addAll(synthetic);
return result.toArray(new Method[result.size()]);
}
@@ -224,63 +212,52 @@ import org.apache.harmony.kernel.vm.ReflectionAccess;
}
}
- /**
- * Finds and returns a method with a given name and signature. Use
- * this with one of the method lists returned by instances of this class.
- *
- * @param list non-null; the list of methods to search through
- * @param parameterTypes non-null; the formal parameter list
- * @return non-null; the matching method
- * @throws NoSuchMethodException thrown if the method does not exist
- */
- public static Method findMethodByName(Method[] list, String name,
- Class<?>[] parameterTypes) throws NoSuchMethodException {
+ public static Member getConstructorOrMethod(Class<?> clazz, String name, boolean recursive,
+ boolean publicOnly, Class<?>[] parameterTypes) throws NoSuchMethodException {
+ if (recursive && !publicOnly) {
+ throw new AssertionError(); // can't lookup non-public members recursively
+ }
if (name == null) {
throw new NullPointerException("name == null");
}
- for (Method method : list) {
- if (method.getName().equals(name)
- && compareClassLists(method.getParameterTypes(), parameterTypes)) {
- return method;
- }
+ if (parameterTypes == null) {
+ parameterTypes = EmptyArray.CLASS;
}
-
- throw new NoSuchMethodException(name);
- }
-
- /**
- * Compares two class lists for equality. Empty and
- * <code>null</code> lists are considered equal. This is useful
- * for matching methods and constructors.
- *
- * <p>TODO: Take into account assignment compatibility?</p>
- *
- * @param a null-ok; the first list of types
- * @param b null-ok; the second list of types
- * @return true if and only if the lists are equal
- */
- public static boolean compareClassLists(Class<?>[] a, Class<?>[] b) {
- if (a == null) {
- return (b == null) || (b.length == 0);
+ for (Class<?> c : parameterTypes) {
+ if (c == null) {
+ throw new NoSuchMethodException("parameter type is null");
+ }
}
-
- int length = a.length;
-
- if (b == null) {
- return (length == 0);
+ Member result = recursive
+ ? getPublicConstructorOrMethodRecursive(clazz, name, parameterTypes)
+ : Class.getDeclaredConstructorOrMethod(clazz, name, parameterTypes);
+ if (result == null || publicOnly && (result.getModifiers() & Modifier.PUBLIC) == 0) {
+ throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
}
+ return result;
+ }
- if (length != b.length) {
- return false;
+ private static Member getPublicConstructorOrMethodRecursive(
+ Class<?> clazz, String name, Class<?>[] parameterTypes) {
+ // search superclasses
+ for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
+ Member result = Class.getDeclaredConstructorOrMethod(c, name, parameterTypes);
+ if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
+ return result;
+ }
}
- for (int i = length - 1; i >= 0; i--) {
- if (a[i] != b[i]) {
- return false;
+ // search implemented interfaces
+ for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
+ for (Class<?> ifc : c.getInterfaces()) {
+ Member result = getPublicConstructorOrMethodRecursive(ifc, name, parameterTypes);
+ if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
+ return result;
+ }
}
}
- return true;
+ return null;
}
/**
@@ -540,17 +517,8 @@ import org.apache.harmony.kernel.vm.ReflectionAccess;
*/
@SuppressWarnings("unchecked")
private T[] callEnumValues() {
- Method method;
-
- try {
- Method[] methods = getDeclaredPublicMethods();
- method = findMethodByName(methods, "values", null);
- method = REFLECT.accessibleClone(method);
- } catch (NoSuchMethodException ex) {
- // This shouldn't happen if the class is a well-formed enum.
- throw new UnsupportedOperationException(ex);
- }
-
+ Method method = (Method) Class.getDeclaredConstructorOrMethod(
+ clazz, "values", EmptyArray.CLASS);
try {
return (T[]) method.invoke((Object[]) null);
} catch (IllegalAccessException ex) {
@@ -581,19 +549,11 @@ import org.apache.harmony.kernel.vm.ReflectionAccess;
* initialization. So instead, we do a direct call into the
* native side.
*/
- Method[] methods = Class.getDeclaredMethods(AccessibleObject.class, false);
-
try {
- Method method = findMethodByName(methods, "getReflectionAccess", null);
+ Method method = (Method) Class.getDeclaredConstructorOrMethod(
+ AccessibleObject.class, "getReflectionAccess", EmptyArray.CLASS);
Class.setAccessibleNoCheck(method, true);
return (ReflectionAccess) method.invoke((Object[]) null);
- } catch (NoSuchMethodException ex) {
- /*
- * This shouldn't happen because the method
- * AccessibleObject.getReflectionAccess() really is defined
- * in this module.
- */
- throw new Error(ex);
} catch (IllegalAccessException ex) {
// This shouldn't happen because the method is "accessible."
throw new Error(ex);
diff --git a/luni/src/main/java/java/lang/Enum.java b/luni/src/main/java/java/lang/Enum.java
index 9a57fd8..838ab85 100644
--- a/luni/src/main/java/java/lang/Enum.java
+++ b/luni/src/main/java/java/lang/Enum.java
@@ -163,8 +163,6 @@ public abstract class Enum<E extends Enum<E>> implements Serializable, Comparabl
throw new NullPointerException("enumType == null || name == null");
}
- enumType.checkPublicMemberAccess();
-
T result = enumType.getClassMembers().getEnumValue(name);
if (result == null) {
if (!enumType.isEnum()) {
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java b/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java
index fae61c7..ed98794 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java
@@ -17,8 +17,9 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Constructor;
+import junit.framework.TestCase;
-public class ConstructorTest extends junit.framework.TestCase {
+public final class ConstructorTest extends TestCase {
public void test_getExceptionTypes() throws Exception {
Constructor<?> constructor = ConstructorTestHelper.class.getConstructor(new Class[0]);
Class[] exceptions = constructor.getExceptionTypes();
@@ -44,8 +45,36 @@ public class ConstructorTest extends junit.framework.TestCase {
assertEquals(expectedParameters[0], parameters[0]);
}
+ public void testGetConstructorWithNullArgumentsArray() throws Exception {
+ Constructor<?> constructor = ConstructorTestHelper.class.getConstructor((Class[]) null);
+ assertEquals(0, constructor.getParameterTypes().length);
+ }
+
+ public void testGetConstructorWithNullArgument() throws Exception {
+ try {
+ ConstructorTestHelper.class.getConstructor(new Class[] { null });
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public void testGetConstructorReturnsDoesNotReturnPrivateConstructor() throws Exception {
+ try {
+ ConstructorTestHelper.class.getConstructor(Object.class, Object.class);
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public void testGetDeclaredConstructorReturnsPrivateConstructor() throws Exception {
+ Constructor<?> constructor = ConstructorTestHelper.class.getDeclaredConstructor(
+ Object.class, Object.class);
+ assertEquals(2, constructor.getParameterTypes().length);
+ }
+
static class ConstructorTestHelper {
public ConstructorTestHelper() throws IndexOutOfBoundsException { }
public ConstructorTestHelper(Object o) { }
+ private ConstructorTestHelper(Object a, Object b) { }
}
}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index 192c79c..0c268ff 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -17,8 +17,9 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Method;
+import junit.framework.TestCase;
-public class MethodTest extends junit.framework.TestCase {
+public final class MethodTest extends TestCase {
// Check that the VM gives useful detail messages.
public void test_invokeExceptions() throws Exception {
Method m = String.class.getMethod("charAt", int.class);
@@ -79,8 +80,100 @@ public class MethodTest extends junit.framework.TestCase {
assertEquals(expectedParameters[0], parameters[0]);
}
- static class MethodTestHelper {
+ public void testGetMethodWithPrivateMethodAndInterfaceMethod() throws Exception {
+ assertEquals(InterfaceA.class, Sub.class.getMethod("a").getDeclaringClass());
+ }
+
+ public void testGetMethodReturnsIndirectlyImplementedInterface() throws Exception {
+ assertEquals(InterfaceA.class, ImplementsC.class.getMethod("a").getDeclaringClass());
+ assertEquals(InterfaceA.class, ExtendsImplementsC.class.getMethod("a").getDeclaringClass());
+ }
+
+ public void testGetDeclaredMethodReturnsIndirectlyImplementedInterface() throws Exception {
+ try {
+ ImplementsC.class.getDeclaredMethod("a").getDeclaringClass();
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ try {
+ ExtendsImplementsC.class.getDeclaredMethod("a").getDeclaringClass();
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public void testGetMethodWithConstructorName() throws Exception {
+ try {
+ MethodTestHelper.class.getMethod("<init>");
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public void testGetMethodWithNullName() throws Exception {
+ try {
+ MethodTestHelper.class.getMethod(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testGetMethodWithNullArgumentsArray() throws Exception {
+ Method m1 = MethodTestHelper.class.getMethod("m1", (Class[]) null);
+ assertEquals(0, m1.getParameterTypes().length);
+ }
+
+ public void testGetMethodWithNullArgument() throws Exception {
+ try {
+ MethodTestHelper.class.getMethod("m2", new Class[] { null });
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public void testGetMethodReturnsInheritedStaticMethod() throws Exception {
+ Method b = Sub.class.getMethod("b");
+ assertEquals(void.class, b.getReturnType());
+ }
+
+ public void testGetDeclaredMethodReturnsPrivateMethods() throws Exception {
+ Method method = Super.class.getDeclaredMethod("a");
+ assertEquals(void.class, method.getReturnType());
+ }
+
+ public void testGetDeclaredMethodDoesNotReturnSuperclassMethods() throws Exception {
+ try {
+ Sub.class.getDeclaredMethod("a");
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public void testGetDeclaredMethodDoesNotReturnImplementedInterfaceMethods() throws Exception {
+ try {
+ InterfaceB.class.getDeclaredMethod("a");
+ fail();
+ } catch (NoSuchMethodException expected) {
+ }
+ }
+
+ public static class MethodTestHelper {
public void m1() throws IndexOutOfBoundsException { }
public void m2(Object o) { }
}
+
+ public static class Super {
+ private void a() {}
+ public static void b() {}
+ }
+ public static interface InterfaceA {
+ void a();
+ }
+ public static abstract class Sub extends Super implements InterfaceA {
+ }
+
+ public static interface InterfaceB extends InterfaceA {}
+ public static interface InterfaceC extends InterfaceB {}
+ public static abstract class ImplementsC implements InterfaceC {}
+ public static abstract class ExtendsImplementsC extends ImplementsC {}
}