Added new method to allow work-arounds for Java bug 4071957; as specified in issue 34351
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@395153 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2330a3343c
commit
fc9b4cc1d8
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package org.apache.commons.lang;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -589,6 +592,53 @@ public class ClassUtils {
|
|||
return getClass(loader, className, initialize );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Returns the desired Method much like <code>Class.getMethod</code>, however
|
||||
* it ensures that the returned Method is from a public class or interface and not
|
||||
* from an anonymous inner class. This means that the Method is invokable and
|
||||
* doesn't fall foul of Java bug
|
||||
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).
|
||||
*
|
||||
* <code><pre>Set set = Collections.unmodifiableSet(...);
|
||||
* Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
|
||||
* Object result = method.invoke(set, new Object[]);</pre></code>
|
||||
* </p>
|
||||
*/
|
||||
public static Method getPublicMethod(Class cls, String methodName, Class parameterTypes[])
|
||||
throws SecurityException, NoSuchMethodException
|
||||
{
|
||||
|
||||
Method declaredMethod = cls.getMethod(methodName, parameterTypes);
|
||||
|
||||
if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
|
||||
return declaredMethod;
|
||||
}
|
||||
|
||||
List candidateClasses = new ArrayList();
|
||||
candidateClasses.addAll(getAllInterfaces(cls));
|
||||
candidateClasses.addAll(getAllSuperclasses(cls));
|
||||
|
||||
for (Iterator iter=candidateClasses.iterator(); iter.hasNext(); ) {
|
||||
Class candidateClass = (Class) iter.next();
|
||||
if (!Modifier.isPublic(candidateClass.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
Method candidateMethod;
|
||||
try {
|
||||
candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
|
||||
} catch (NoSuchMethodException e) {
|
||||
continue;
|
||||
}
|
||||
if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
|
||||
return candidateMethod;
|
||||
}
|
||||
}
|
||||
|
||||
String message = "Can't find an public method for " + methodName + " " + ArrayUtils.toString(parameterTypes);
|
||||
throw new NoSuchMethodException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a class name to a JLS stle class name.
|
||||
*
|
||||
|
|
|
@ -16,12 +16,16 @@
|
|||
package org.apache.commons.lang;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
@ -520,4 +524,35 @@ public class ClassUtilsTest extends TestCase {
|
|||
return URLClassLoader.newInstance(urlScl.getURLs(), null);
|
||||
}
|
||||
|
||||
// Show the Java bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957
|
||||
// We may have to delete this if a JDK fixes the bug.
|
||||
public void testShowJavaBug() throws Exception {
|
||||
// Tests with Collections$UnmodifiableSet
|
||||
Set set = Collections.unmodifiableSet(new HashSet());
|
||||
Method isEmptyMethod = set.getClass().getMethod("isEmpty", new Class[0]);
|
||||
try {
|
||||
isEmptyMethod.invoke(set, new Object[0]);
|
||||
fail("Failed to throw IllegalAccessException as expected");
|
||||
} catch(IllegalAccessException iae) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetPublicMethod() throws Exception {
|
||||
// Tests with Collections$UnmodifiableSet
|
||||
Set set = Collections.unmodifiableSet(new HashSet());
|
||||
Method isEmptyMethod = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
|
||||
assertTrue(Modifier.isPublic(isEmptyMethod.getDeclaringClass().getModifiers()));
|
||||
|
||||
try {
|
||||
isEmptyMethod.invoke(set, new Object[0]);
|
||||
} catch(java.lang.IllegalAccessException iae) {
|
||||
fail("Should not have thrown IllegalAccessException");
|
||||
}
|
||||
|
||||
// Tests with a public Class
|
||||
Method toStringMethod = ClassUtils.getPublicMethod(Object.class, "toString", new Class[0]);
|
||||
assertEquals(Object.class.getMethod("toString", new Class[0]), toStringMethod);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue