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"));
+    }
 }