diff options
author | Jesse Wilson <jessewilson@google.com> | 2011-02-23 13:33:25 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-02-23 13:33:25 -0800 |
commit | 217766d68f160dd03def5d5f983d5330c24a3ed7 (patch) | |
tree | 853931b70c7d9e1e3855aaef9e599e8bbc87fbb7 /luni | |
parent | 482d294ebd5dff55f5397d5991f9f0e3808e5cac (diff) | |
parent | 11229f6af89fc54e70675fcab098b1572d6e539e (diff) | |
download | libcore-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.java | 150 | ||||
-rw-r--r-- | luni/src/main/java/java/lang/ClassLoader.java | 8 | ||||
-rw-r--r-- | luni/src/main/java/java/lang/ClassMembers.java | 126 | ||||
-rw-r--r-- | luni/src/main/java/java/lang/Enum.java | 2 | ||||
-rw-r--r-- | luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java | 31 | ||||
-rw-r--r-- | luni/src/test/java/libcore/java/lang/reflect/MethodTest.java | 97 |
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 {} } |