PR: Bugzilla Bug 26943 [patch] Class and Package Comparators for ClassUtils
Submitted by: alban.peignier Reviewed by: Gary Gregory git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137791 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
89112beabd
commit
0fcfcfdc65
|
@ -54,6 +54,7 @@
|
||||||
package org.apache.commons.lang;
|
package org.apache.commons.lang;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -68,27 +69,27 @@ import java.util.Map;
|
||||||
* @author Gary Gregory
|
* @author Gary Gregory
|
||||||
* @author Norm Deane
|
* @author Norm Deane
|
||||||
* @since 2.0
|
* @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 {
|
public class ClassUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The package separator character: <code>.</code>.</p>
|
* <p>The package separator character: <code>'.' == {@value}</code>.</p>
|
||||||
*/
|
*/
|
||||||
public static final char PACKAGE_SEPARATOR_CHAR = '.';
|
public static final char PACKAGE_SEPARATOR_CHAR = '.';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The package separator String: <code>.</code>.</p>
|
* <p>The package separator String: <code>"."</code>.</p>
|
||||||
*/
|
*/
|
||||||
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
|
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The inner class separator character: <code>$</code>.</p>
|
* <p>The inner class separator character: <code>'$' == {@value}</code>.</p>
|
||||||
*/
|
*/
|
||||||
public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
|
public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The inner class separator String: <code>$</code>.</p>
|
* <p>The inner class separator String: <code>"$"</code>.</p>
|
||||||
*/
|
*/
|
||||||
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
|
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);
|
return (cls.getName().indexOf(INNER_CLASS_SEPARATOR_CHAR) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two <code>Class</code>s by name.
|
||||||
|
*/
|
||||||
|
public static final Comparator CLASS_NAME_COMPARATOR = new Comparator() {
|
||||||
|
/**
|
||||||
|
* Compares two <code>Class</code>s by name.
|
||||||
|
*
|
||||||
|
* @throws ClassCastException
|
||||||
|
* If <code>o1</code> or <code>o2</code> are not <code>Class</code>
|
||||||
|
* 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 <code>Package</code>s by name.
|
||||||
|
*/
|
||||||
|
public static final Comparator PACKAGE_NAME_COMPARATOR = new Comparator() {
|
||||||
|
/**
|
||||||
|
* Compares two <code>Package</code>s by name.
|
||||||
|
*
|
||||||
|
* @throws ClassCastException
|
||||||
|
* If <code>o1</code> or <code>o2</code> are not <code>Package</code>
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,12 @@
|
||||||
package org.apache.commons.lang;
|
package org.apache.commons.lang;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -63,12 +67,14 @@ import junit.framework.Test;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import junit.textui.TestRunner;
|
import junit.textui.TestRunner;
|
||||||
|
import org.apache.commons.lang.enum.ColorEnum;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests {@link org.apache.commons.lang.ClassUtils}.
|
* Unit tests {@link org.apache.commons.lang.ClassUtils}.
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @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 {
|
public class ClassUtilsTest extends TestCase {
|
||||||
|
|
||||||
|
@ -411,6 +417,100 @@ public class ClassUtilsTest extends TestCase {
|
||||||
ClassUtils.primitiveToWrapper(null));
|
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 List getAssignableFrom(List classes, Class superclass) {
|
||||||
// public static boolean isAssignable(Class[] classArray, Class[] toClassArray) {
|
// public static boolean isAssignable(Class[] classArray, Class[] toClassArray) {
|
||||||
// public static boolean isAssignable(Class cls, Class toClass) {
|
// public static boolean isAssignable(Class cls, Class toClass) {
|
||||||
|
|
|
@ -55,7 +55,6 @@ package org.apache.commons.lang.enum;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -66,14 +65,15 @@ import junit.framework.AssertionFailedError;
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
import org.apache.commons.lang.ClassUtilsTest;
|
||||||
import org.apache.commons.lang.SerializationUtils;
|
import org.apache.commons.lang.SerializationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test cases for the {@link Enum} class.
|
* Test cases for the {@link Enum} class.
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @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 {
|
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
|
// the SAME class as the getEnumList(). The references in the outer class
|
||||||
// are just extra references.
|
// 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:
|
// Sanity check:
|
||||||
ColorEnum.RED.equals(ColorEnum.RED);
|
ColorEnum.RED.equals(ColorEnum.RED);
|
||||||
assertNotNull(ColorEnum.class.getClassLoader());
|
assertNotNull(ColorEnum.class.getClassLoader());
|
||||||
// set up:
|
// 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);
|
assertNotNull(classLoader);
|
||||||
assertFalse(classLoader.equals(ColorEnum.class.getClassLoader()));
|
assertFalse(classLoader.equals(ColorEnum.class.getClassLoader()));
|
||||||
Class otherColorEnumClass = classLoader.loadClass("org.apache.commons.lang.enum.ColorEnum");
|
Class otherColorEnumClass = classLoader.loadClass("org.apache.commons.lang.enum.ColorEnum");
|
||||||
|
@ -492,24 +524,31 @@ public final class EnumTest extends TestCase {
|
||||||
assertNotNull(otherColorEnumClass.getClassLoader());
|
assertNotNull(otherColorEnumClass.getClassLoader());
|
||||||
assertTrue(classLoader.equals(otherColorEnumClass.getClassLoader()));
|
assertTrue(classLoader.equals(otherColorEnumClass.getClassLoader()));
|
||||||
assertFalse(otherColorEnumClass.getClassLoader().equals(ColorEnum.class.getClassLoader()));
|
assertFalse(otherColorEnumClass.getClassLoader().equals(ColorEnum.class.getClassLoader()));
|
||||||
Method method = otherColorEnumClass.getMethod("getEnum", new Class[]{String.class});
|
Method method = otherColorEnumClass.getMethod("getEnum", new Class[]{String.class});
|
||||||
Object enumObject = method.invoke(otherColorEnumClass, new Object[]{"Red"});
|
Object enumObject = method.invoke(otherColorEnumClass, new Object[]{color});
|
||||||
assertNotNull(enumObject);
|
assertNotNull(enumObject);
|
||||||
// the real test, part 1.
|
assertFalse(ColorEnum.class.equals(enumObject.getClass()));
|
||||||
try {
|
assertFalse(ColorEnum.class == enumObject.getClass());
|
||||||
ColorEnum testCase = (ColorEnum)enumObject;
|
return 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() {
|
public void testEqualsToWrongInstance() {
|
||||||
assertEquals(false, ColorEnum.RED.equals("test"));
|
for (Iterator iter = ColorEnum.iterator(); iter.hasNext();) {
|
||||||
assertEquals(false, ColorEnum.RED.equals(new Integer(1)));
|
ColorEnum element = (ColorEnum) iter.next();
|
||||||
assertEquals(false, ColorEnum.RED.equals(new Boolean(true)));
|
this.testEqualsToWrongInstance(element);
|
||||||
assertEquals(false, ColorEnum.RED.equals(new StringBuffer("test")));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue