LANG-259 - Fix compareTo to check the type is the same

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@432748 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Stephen Colebourne 2006-08-18 22:21:47 +00:00
parent d9c6932a6e
commit 07b7795b33
4 changed files with 233 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2005 The Apache Software Foundation. * Copyright 2002-2006 The Apache Software Foundation.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,6 +15,8 @@
*/ */
package org.apache.commons.lang.enums; package org.apache.commons.lang.enums;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -166,6 +168,10 @@ public final int getValue() {
* <p>The default ordering is numeric by value, but this * <p>The default ordering is numeric by value, but this
* can be overridden by subclasses.</p> * can be overridden by subclasses.</p>
* *
* <p>NOTE: From v2.2 the enums must be of the same type.
* If the parameter is in a different class loader than this instance,
* reflection is used to compare the values.</p>
*
* @see java.lang.Comparable#compareTo(Object) * @see java.lang.Comparable#compareTo(Object)
* @param other the other object to compare to * @param other the other object to compare to
* @return -ve if this is less than the other object, +ve if greater than, * @return -ve if this is less than the other object, +ve if greater than,
@ -174,9 +180,40 @@ public final int getValue() {
* @throws NullPointerException if other is <code>null</code> * @throws NullPointerException if other is <code>null</code>
*/ */
public int compareTo(Object other) { public int compareTo(Object other) {
if (other == this) {
return 0;
}
if (other.getClass() != this.getClass()) {
if (other.getClass().getName().equals(this.getClass().getName())) {
return iValue - getValueInOtherClassLoader(other);
}
throw new ClassCastException(
"Different enum class '" + ClassUtils.getShortClassName(other.getClass()) + "'");
}
return iValue - ((ValuedEnum) other).iValue; return iValue - ((ValuedEnum) other).iValue;
} }
/**
* <p>Use reflection to return an objects value.</p>
*
* @param other the object to determine the value for
* @return the value
*/
private int getValueInOtherClassLoader(Object other) {
try {
Method mth = other.getClass().getMethod("getValue", null);
Integer value = (Integer) mth.invoke(other, null);
return value.intValue();
} catch (NoSuchMethodException e) {
// ignore - should never happen
} catch (IllegalAccessException e) {
// ignore - should never happen
} catch (InvocationTargetException e) {
// ignore - should never happen
}
throw new IllegalStateException("This should not happen");
}
/** /**
* <p>Human readable description of this <code>Enum</code> item.</p> * <p>Human readable description of this <code>Enum</code> item.</p>
* *

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2005 The Apache Software Foundation. * Copyright 2004-2006 The Apache Software Foundation.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,6 +15,8 @@
*/ */
package org.apache.commons.lang.enums; package org.apache.commons.lang.enums;
import java.net.URLClassLoader;
import junit.framework.Test; import junit.framework.Test;
import junit.framework.TestCase; import junit.framework.TestCase;
import junit.framework.TestSuite; import junit.framework.TestSuite;
@ -88,6 +90,34 @@ public void testEquals() {
assertEquals(false, CarColorEnum.RED.equals(new TotallyUnrelatedClass("some"))); assertEquals(false, CarColorEnum.RED.equals(new TotallyUnrelatedClass("some")));
} }
public void testEquals_classloader_equal() throws Exception {
ClassLoader cl = ColorEnum.class.getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader urlCL = (URLClassLoader) cl;
URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);
URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);
Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ColorEnum");
Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ColorEnum");
Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);
Object blue2 = otherEnumClass2.getDeclaredField("BLUE").get(null);
assertEquals(true, blue1.equals(blue2));
}
}
public void testEquals_classloader_different() throws Exception {
ClassLoader cl = ColorEnum.class.getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader urlCL = (URLClassLoader) cl;
URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);
URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);
Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ColorEnum");
Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ColorEnum");
Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);
Object blue2 = otherEnumClass2.getDeclaredField("RED").get(null);
assertEquals(false, blue1.equals(blue2));
}
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
public void testCompareTo() { public void testCompareTo() {
try { try {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2005 The Apache Software Foundation. * Copyright 2002-2006 The Apache Software Foundation.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,6 +15,7 @@
*/ */
package org.apache.commons.lang.enums; package org.apache.commons.lang.enums;
import java.net.URLClassLoader;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -64,11 +65,103 @@ public void testCompareTo() {
assertTrue(ValuedColorEnum.BLUE.compareTo(ValuedColorEnum.RED) > 0); assertTrue(ValuedColorEnum.BLUE.compareTo(ValuedColorEnum.RED) > 0);
} }
public void testCompareTo_classloader_equal() throws Exception {
ClassLoader cl = ValuedColorEnum.class.getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader urlCL = (URLClassLoader) cl;
URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);
URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);
Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);
Object blue2 = otherEnumClass2.getDeclaredField("BLUE").get(null);
assertTrue(((Comparable) blue1).compareTo(blue2) == 0);
}
}
public void testCompareTo_classloader_different() throws Exception {
ClassLoader cl = ValuedColorEnum.class.getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader urlCL = (URLClassLoader) cl;
URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);
URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);
Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);
Object blue2 = otherEnumClass2.getDeclaredField("RED").get(null);
assertTrue(((Comparable) blue1).compareTo(blue2) != 0);
}
}
public void testCompareTo_nonEnumType() {
try {
ValuedColorEnum.BLUE.compareTo(new TotallyUnrelatedClass(ValuedColorEnum.BLUE.getValue()));
fail();
} catch (ClassCastException ex) {
// expected
}
}
public void testCompareTo_otherEnumType() {
try {
ValuedColorEnum.BLUE.compareTo(ValuedLanguageEnum.ENGLISH);
fail();
} catch (ClassCastException ex) {
// expected
}
}
public void testCompareTo_otherType() {
try {
ValuedColorEnum.BLUE.compareTo("Blue");
fail();
} catch (ClassCastException ex) {
// expected
}
}
public void testCompareTo_null() {
try {
ValuedColorEnum.BLUE.compareTo(null);
fail();
} catch (NullPointerException ex) {
// expected
}
}
public void testEquals() { public void testEquals() {
assertSame(ValuedColorEnum.RED, ValuedColorEnum.RED); assertSame(ValuedColorEnum.RED, ValuedColorEnum.RED);
assertSame(ValuedColorEnum.getEnum("Red"), ValuedColorEnum.RED); assertSame(ValuedColorEnum.getEnum("Red"), ValuedColorEnum.RED);
} }
public void testEquals_classloader_equal() throws Exception {
ClassLoader cl = ValuedColorEnum.class.getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader urlCL = (URLClassLoader) cl;
URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);
URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);
Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);
Object blue2 = otherEnumClass2.getDeclaredField("BLUE").get(null);
assertEquals(true, blue1.equals(blue2));
}
}
public void testEquals_classloader_different() throws Exception {
ClassLoader cl = ValuedColorEnum.class.getClassLoader();
if (cl instanceof URLClassLoader) {
URLClassLoader urlCL = (URLClassLoader) cl;
URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);
URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);
Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);
Object blue2 = otherEnumClass2.getDeclaredField("RED").get(null);
assertEquals(false, blue1.equals(blue2));
}
}
public void testToString() { public void testToString() {
String toString = ValuedColorEnum.RED.toString(); String toString = ValuedColorEnum.RED.toString();
assertEquals("ValuedColorEnum[Red=1]", toString); assertEquals("ValuedColorEnum[Red=1]", toString);
@ -132,4 +225,17 @@ public void testSerialization() {
assertSame(ValuedColorEnum.BLUE, SerializationUtils.clone(ValuedColorEnum.BLUE)); assertSame(ValuedColorEnum.BLUE, SerializationUtils.clone(ValuedColorEnum.BLUE));
} }
//-----------------------------------------------------------------------s
static class TotallyUnrelatedClass {
private final int value;
public TotallyUnrelatedClass(final int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
} }

View File

@ -0,0 +1,56 @@
/*
* Copyright 2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang.enums;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Language enumeration.
*
* @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
* @version $Id: ValuedColorEnum.java 161244 2005-04-14 06:16:36Z ggregory $
*/
public final class ValuedLanguageEnum extends ValuedEnum {
public static final ValuedLanguageEnum ENGLISH = new ValuedLanguageEnum("English", 1);
public static final ValuedLanguageEnum FRENCH = new ValuedLanguageEnum("French", 2);
public static final ValuedLanguageEnum GERMAN = new ValuedLanguageEnum("German", 3);
private ValuedLanguageEnum(String color, int value) {
super(color, value);
}
public static ValuedLanguageEnum getEnum(String color) {
return (ValuedLanguageEnum) getEnum(ValuedLanguageEnum.class, color);
}
public static ValuedLanguageEnum getEnum(int value) {
return (ValuedLanguageEnum) getEnum(ValuedLanguageEnum.class, value);
}
public static Map getEnumMap() {
return getEnumMap(ValuedLanguageEnum.class);
}
public static List getEnumList() {
return getEnumList(ValuedLanguageEnum.class);
}
public static Iterator iterator() {
return iterator(ValuedLanguageEnum.class);
}
}