PR: http://issues.apache.org/bugzilla/show_bug.cgi?id=26876
[lang] Enum.equals does not handle different class loaders.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137776 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/commons/lang/enum/Enum.java b/src/java/org/apache/commons/lang/enum/Enum.java
index 6162b90..43dbecf 100644
--- a/src/java/org/apache/commons/lang/enum/Enum.java
+++ b/src/java/org/apache/commons/lang/enum/Enum.java
@@ -267,7 +267,7 @@
* @author Chris Webb
* @author Mike Bowler
* @since 1.0
- * @version $Id: Enum.java,v 1.23 2003/11/29 15:03:54 scolebourne Exp $
+ * @version $Id: Enum.java,v 1.24 2004/02/12 00:45:09 ggregory Exp $
*/
public abstract class Enum implements Comparable, Serializable {
@@ -567,34 +567,27 @@
} else if (other == null) {
return false;
} else if (other.getClass() == this.getClass()) {
- // shouldn't happen, but...
+ // Ok to do a class cast to Enum here since the test above
+ // guarantee both
+ // classes are in the same class loader.
return iName.equals(((Enum) other).iName);
- } else if (((Enum) other).getEnumClass().getName().equals(getEnumClass().getName())) {
- // different classloaders
- try {
- // try to avoid reflection
- return iName.equals(((Enum) other).iName);
-
- } catch (ClassCastException ex) {
- // use reflection
- try {
- Method mth = other.getClass().getMethod("getName", null);
- String name = (String) mth.invoke(other, null);
- return iName.equals(name);
- } catch (NoSuchMethodException ex2) {
- // ignore - should never happen
- } catch (IllegalAccessException ex2) {
- // ignore - should never happen
- } catch (InvocationTargetException ex2) {
- // ignore - should never happen
- }
- return false;
- }
} else {
+ // This and other are in different class loaders, we must use reflection.
+ try {
+ Method mth = other.getClass().getMethod("getName", null);
+ String name = (String) mth.invoke(other, null);
+ return iName.equals(name);
+ } catch (NoSuchMethodException ex2) {
+ // ignore - should never happen
+ } catch (IllegalAccessException ex2) {
+ // ignore - should never happen
+ } catch (InvocationTargetException ex2) {
+ // ignore - should never happen
+ }
return false;
}
}
-
+
/**
* <p>Returns a suitable hashCode for the enumeration.</p>
*
diff --git a/src/test/org/apache/commons/lang/enum/EnumTest.java b/src/test/org/apache/commons/lang/enum/EnumTest.java
index 2dcdcb5..b358470 100644
--- a/src/test/org/apache/commons/lang/enum/EnumTest.java
+++ b/src/test/org/apache/commons/lang/enum/EnumTest.java
@@ -53,6 +53,10 @@
*/
package org.apache.commons.lang.enum;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -62,14 +66,13 @@
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
-
import org.apache.commons.lang.SerializationUtils;
/**
* Test cases for the {@link Enum} class.
*
* @author Stephen Colebourne
- * @version $Id: EnumTest.java,v 1.12 2003/11/29 15:03:54 scolebourne Exp $
+ * @version $Id: EnumTest.java,v 1.13 2004/02/12 00:45:09 ggregory Exp $
*/
public final class EnumTest extends TestCase {
@@ -465,4 +468,42 @@
// are just extra references.
}
+ public void testEqualsWithDifferentClassLoaders() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+ // Sanity check:
+ ColorEnum.RED.equals(ColorEnum.RED);
+ assertNotNull(ColorEnum.class.getClassLoader());
+ // set up:
+ ClassLoader scl = ClassLoader.getSystemClassLoader();
+ if (!(scl instanceof URLClassLoader)) {
+ fail("Need a better test set up.");
+ }
+ URLClassLoader urlScl = (URLClassLoader)scl;
+ ClassLoader classLoader = URLClassLoader.newInstance(urlScl.getURLs(), null);
+ assertNotNull(classLoader);
+ assertFalse(classLoader.equals(ColorEnum.class.getClassLoader()));
+ Class otherColorEnumClass = classLoader.loadClass("org.apache.commons.lang.enum.ColorEnum");
+ assertNotNull(otherColorEnumClass);
+ assertNotNull(otherColorEnumClass.getClassLoader());
+ assertTrue(classLoader.equals(otherColorEnumClass.getClassLoader()));
+ assertFalse(otherColorEnumClass.getClassLoader().equals(ColorEnum.class.getClassLoader()));
+ Method method = otherColorEnumClass.getMethod("getEnum", new Class[]{String.class});
+ Object enumObject = method.invoke(otherColorEnumClass, new Object[]{"Red"});
+ assertNotNull(enumObject);
+ // the real test, part 1.
+ try {
+ ColorEnum testCase = (ColorEnum)enumObject;
+ fail("Should have thrown a ClassCastException");
+ } catch (ClassCastException e) {
+ // normal.
+ }
+ // the real test, part 2.
+ assertEquals("The two objects should match even though they are from different class loaders", ColorEnum.RED, enumObject);
+ }
+
+ public void testEqualsToWrongInstance() {
+ ColorEnum.RED.equals("test");
+ ColorEnum.RED.equals(new Integer(1));
+ ColorEnum.RED.equals(new Boolean(true));
+ ColorEnum.RED.equals(new StringBuffer("test"));
+ }
}