diff --git a/src/java/org/apache/commons/lang/ClassUtils.java b/src/java/org/apache/commons/lang/ClassUtils.java index 12883f66c..65de3b9fb 100644 --- a/src/java/org/apache/commons/lang/ClassUtils.java +++ b/src/java/org/apache/commons/lang/ClassUtils.java @@ -54,6 +54,7 @@ package org.apache.commons.lang; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -68,27 +69,27 @@ import java.util.Map; * @author Gary Gregory * @author Norm Deane * @since 2.0 - * @version $Id: ClassUtils.java,v 1.23 2003/10/23 21:03:43 scolebourne Exp $ + * @version $Id: ClassUtils.java,v 1.24 2004/02/15 00:51:38 ggregory Exp $ */ public class ClassUtils { /** - *

The package separator character: ..

+ *

The package separator character: '.' == {@value}.

*/ public static final char PACKAGE_SEPARATOR_CHAR = '.'; /** - *

The package separator String: ..

+ *

The package separator String: ".".

*/ public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); /** - *

The inner class separator character: $.

+ *

The inner class separator character: '$' == {@value}.

*/ public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; /** - *

The inner class separator String: $.

+ *

The inner class separator String: "$".

*/ public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); @@ -564,4 +565,52 @@ public class ClassUtils { return (cls.getName().indexOf(INNER_CLASS_SEPARATOR_CHAR) >= 0); } + /** + * Compares two Classs by name. + */ + public static final Comparator CLASS_NAME_COMPARATOR = new Comparator() { + /** + * Compares two Classs by name. + * + * @throws ClassCastException + * If o1 or o2 are not Class + * instances. + */ + public int compare(Object o1, Object o2) { + Class class1 = (Class) o1; + Class class2 = (Class) o2; + if (class1 == null) { + return class2 == null ? 0 : -1; + } + if (class2 == null) { + return 1; + } + return class1.getName().compareTo(class2.getName()); + } + }; + + /** + * Compares two Packages by name. + */ + public static final Comparator PACKAGE_NAME_COMPARATOR = new Comparator() { + /** + * Compares two Packages by name. + * + * @throws ClassCastException + * If o1 or o2 are not Package + * instances. + */ + public int compare(Object o1, Object o2) { + Package package1 = (Package) o1; + Package package2 = (Package) o2; + if (package1 == null) { + return package2 == null ? 0 : -1; + } + if (package2 == null) { + return 1; + } + return package1.getName().compareTo(package2.getName()); + } + }; + } diff --git a/src/test/org/apache/commons/lang/ClassUtilsTest.java b/src/test/org/apache/commons/lang/ClassUtilsTest.java index cde1903ee..1439f368a 100644 --- a/src/test/org/apache/commons/lang/ClassUtilsTest.java +++ b/src/test/org/apache/commons/lang/ClassUtilsTest.java @@ -54,8 +54,12 @@ package org.apache.commons.lang; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -63,12 +67,14 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import junit.textui.TestRunner; +import org.apache.commons.lang.enum.ColorEnum; /** * Unit tests {@link org.apache.commons.lang.ClassUtils}. * * @author Stephen Colebourne - * @version $Id: ClassUtilsTest.java,v 1.7 2003/10/23 21:03:44 scolebourne Exp $ + * @author Gary D. Gregory + * @version $Id: ClassUtilsTest.java,v 1.8 2004/02/15 00:51:37 ggregory Exp $ */ public class ClassUtilsTest extends TestCase { @@ -411,6 +417,100 @@ public class ClassUtilsTest extends TestCase { ClassUtils.primitiveToWrapper(null)); } + public void testClassComparator() { + Comparator comparator = ClassUtils.CLASS_NAME_COMPARATOR; + Class smallClass = java.lang.Boolean.class; + Class bigClass = java.util.Set.class; + + assertTrue(comparator.compare(smallClass, smallClass) == 0); + assertTrue(comparator.compare(bigClass, smallClass) > 0); + assertTrue(comparator.compare(smallClass, bigClass) < 0); + + assertTrue(comparator.compare(smallClass, null) > 0); + assertTrue(comparator.compare(null, smallClass) < 0); + + assertComparatorContract(comparator, smallClass, smallClass); + assertComparatorContract(comparator, bigClass, bigClass); + assertComparatorContract(comparator, smallClass, bigClass); + } + + public void testPackageComparator() { + Comparator comparator = ClassUtils.PACKAGE_NAME_COMPARATOR; + Package smallPackage = java.lang.Boolean.class.getPackage(); + Package bigPackage = java.util.Set.class.getPackage(); + + assertTrue(comparator.compare(smallPackage, smallPackage) == 0); + assertTrue(comparator.compare(bigPackage, smallPackage) > 0); + assertTrue(comparator.compare(smallPackage, bigPackage) < 0); + + assertTrue(comparator.compare(smallPackage, null) > 0); + assertTrue(comparator.compare(null, smallPackage) < 0); + + assertComparatorContract(comparator, smallPackage, smallPackage); + assertComparatorContract(comparator, bigPackage, bigPackage); + assertComparatorContract(comparator, smallPackage, bigPackage); + } + + public void testPackageNameComparatorWithDifferentClassLoaders() throws SecurityException, IllegalArgumentException, ClassNotFoundException { + Comparator comparator = ClassUtils.PACKAGE_NAME_COMPARATOR; + Package p1 = java.lang.Boolean.class.getPackage(); + Package p2 = java.util.Set.class.getPackage(); + ClassLoader classLoader = newSystemClassLoader(); + Object p1Other = this.getPackage(classLoader, "java.lang.Boolean"); + Object p2Other = this.getPackage(classLoader, "java.util.Set"); + // all here + assertComparatorContract(comparator, p1, p1); + assertComparatorContract(comparator, p2, p2); + assertComparatorContract(comparator, p1, p2); + // all other + assertComparatorContract(comparator, p1Other, p1Other); + assertComparatorContract(comparator, p2Other, p2Other); + assertComparatorContract(comparator, p1Other, p2Other); + // p1 and p1Other + assertComparatorContract(comparator, p1, p1Other); + assertComparatorContract(comparator, p2, p2); + assertComparatorContract(comparator, p1Other, p2); + // p2 and p2Other + assertComparatorContract(comparator, p1, p1); + assertComparatorContract(comparator, p2, p2Other); + assertComparatorContract(comparator, p1, p2Other); + } + + Object getPackage(ClassLoader classLoader, String className) throws ClassNotFoundException, SecurityException, + IllegalArgumentException { + // Sanity check: + assertNotNull(Package.getPackage("java.lang")); + Package.getPackage("java.lang").equals(Package.getPackage("java.lang")); + // set up: + assertNotNull(classLoader); + Class otherClass = classLoader.loadClass(className); + assertNotNull(otherClass); + Object otherPackage = otherClass.getPackage(); + assertNotNull(otherPackage); + return otherPackage; + } + + /** + * The ordering imposed by a Comparator c on a set of elements S is said to + * be consistent with equals if and only if (compare((Object)e1, + * (Object)e2)==0) has the same boolean value as e1.equals((Object)e2) for + * every e1 and e2 in S. + * + * http://java.sun.com/j2se/1.3/docs/api/java/util/Comparator.html + */ + public void assertComparatorContract(Comparator comparator, Object e1, Object e2) { + assertEquals(comparator.compare(e1, e2) == 0, e1.equals(e2)); + } + + public static ClassLoader newSystemClassLoader() throws SecurityException, IllegalArgumentException { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + if (!(scl instanceof URLClassLoader)) { + fail("Need a better test set up."); + } + URLClassLoader urlScl = (URLClassLoader)scl; + return URLClassLoader.newInstance(urlScl.getURLs(), null); + } + // public static List getAssignableFrom(List classes, Class superclass) { // public static boolean isAssignable(Class[] classArray, Class[] toClassArray) { // public static boolean isAssignable(Class cls, Class toClass) { diff --git a/src/test/org/apache/commons/lang/enum/EnumTest.java b/src/test/org/apache/commons/lang/enum/EnumTest.java index 16961e0ba..6268f001b 100644 --- a/src/test/org/apache/commons/lang/enum/EnumTest.java +++ b/src/test/org/apache/commons/lang/enum/EnumTest.java @@ -55,7 +55,6 @@ package org.apache.commons.lang.enum; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -66,14 +65,15 @@ import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; - +import org.apache.commons.lang.ClassUtilsTest; import org.apache.commons.lang.SerializationUtils; /** * Test cases for the {@link Enum} class. * * @author Stephen Colebourne - * @version $Id: EnumTest.java,v 1.15 2004/02/13 23:17:45 scolebourne Exp $ + * @author Gary D. Gregory + * @version $Id: EnumTest.java,v 1.16 2004/02/15 00:51:38 ggregory Exp $ */ public final class EnumTest extends TestCase { @@ -473,18 +473,50 @@ public final class EnumTest extends TestCase { // the SAME class as the getEnumList(). The references in the outer class // are just extra references. } + + public void testColorEnumEqualsWithDifferentClassLoaders() throws SecurityException, IllegalArgumentException, + ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { + this.testEqualsTrueWithDifferentClassLoaders(ColorEnum.BLUE); + this.testEqualsTrueWithDifferentClassLoaders(ColorEnum.GREEN); + this.testEqualsTrueWithDifferentClassLoaders(ColorEnum.RED); + } - public void testEqualsWithDifferentClassLoaders() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { + void testEqualsTrueWithDifferentClassLoaders(ColorEnum colorEnum) throws ClassNotFoundException, SecurityException, + NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { + // Sanity checks: + assertTrue(colorEnum.equals(colorEnum)); + assertNotNull(ColorEnum.class.getClassLoader()); + // set up: + ClassLoader classLoader = ClassUtilsTest.newSystemClassLoader(); + Object enumObjectFromOtherClassLoader = this.getColorEnum(classLoader, colorEnum.getName()); + // the real test, part 1. + try { + ColorEnum testCase = (ColorEnum) enumObjectFromOtherClassLoader; + fail("Should have thrown a ClassCastException for " + testCase); + } catch (ClassCastException e) { + // normal. + } + // the real test, part 2. + assertEquals("The two objects should match even though they are from different class loaders", colorEnum, + enumObjectFromOtherClassLoader); + // the real test, part 3. + int falseCount = 0; + for (Iterator iter = ColorEnum.iterator(); iter.hasNext();) { + ColorEnum element = (ColorEnum) iter.next(); + if (!colorEnum.equals(element)) { + falseCount++; + assertFalse(enumObjectFromOtherClassLoader.equals(element)); + } + } + assertEquals(ColorEnum.getEnumList().size() - 1, falseCount); + } + + Object getColorEnum(ClassLoader classLoader, String color) 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"); @@ -492,24 +524,31 @@ public final class EnumTest extends TestCase { 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"}); + Method method = otherColorEnumClass.getMethod("getEnum", new Class[]{String.class}); + Object enumObject = method.invoke(otherColorEnumClass, new Object[]{color}); 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); + assertFalse(ColorEnum.class.equals(enumObject.getClass())); + assertFalse(ColorEnum.class == enumObject.getClass()); + return enumObject; } - + public void testEqualsToWrongInstance() { - assertEquals(false, ColorEnum.RED.equals("test")); - assertEquals(false, ColorEnum.RED.equals(new Integer(1))); - assertEquals(false, ColorEnum.RED.equals(new Boolean(true))); - assertEquals(false, ColorEnum.RED.equals(new StringBuffer("test"))); + for (Iterator iter = ColorEnum.iterator(); iter.hasNext();) { + ColorEnum element = (ColorEnum) iter.next(); + this.testEqualsToWrongInstance(element); + } + } + + void testEqualsToWrongInstance(ColorEnum colorEnum) { + assertEquals(false, colorEnum.equals("test")); + assertEquals(false, colorEnum.equals(new Integer(1))); + assertEquals(false, colorEnum.equals(new Boolean(true))); + assertEquals(false, colorEnum.equals(new StringBuffer("test"))); + assertEquals(false, colorEnum.equals(new Object())); + assertEquals(false, colorEnum.equals(null)); + assertEquals(false, colorEnum.equals("")); + assertEquals(false, colorEnum.equals(ColorEnum.getEnum(null))); + assertEquals(false, colorEnum.equals(ColorEnum.getEnum(""))); + assertEquals(false, colorEnum.equals(ColorEnum.getEnum("This ColorEnum does not exist."))); } }