Rework Functional Enums to work on JDK1.2
bug 19030 git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137570 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
cf7f46f654
commit
8b1992ee2f
|
@ -75,9 +75,12 @@ import org.apache.commons.lang.StringUtils;
|
||||||
* however that a more robust type-safe class-based solution can be designed. This
|
* however that a more robust type-safe class-based solution can be designed. This
|
||||||
* class follows the basic Java type-safe enumeration pattern.</p>
|
* class follows the basic Java type-safe enumeration pattern.</p>
|
||||||
*
|
*
|
||||||
* <p><em>NOTE:</em>Due to the way in which Java ClassLoaders work, comparing Enum objects
|
* <p><em>NOTE:</em>Due to the way in which Java ClassLoaders work, comparing
|
||||||
* should always be done using the equals() method, not ==. The equals() method will
|
* Enum objects should always be done using <code>equals()</code>, not <code>==</code>.
|
||||||
* try == first so in most cases the effect is the same.</p>
|
* The equals() method will try == first so in most cases the effect is the same.</p>
|
||||||
|
*
|
||||||
|
* <p>Of course, if you actually want (or don't mind) Enums in different class
|
||||||
|
* loaders being non-equal, then you can use <code>==</code>.</p>
|
||||||
*
|
*
|
||||||
* <h4>Simple Enums</h4>
|
* <h4>Simple Enums</h4>
|
||||||
*
|
*
|
||||||
|
@ -125,7 +128,7 @@ import org.apache.commons.lang.StringUtils;
|
||||||
* superclass and subclass.</p>
|
* superclass and subclass.</p>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* public class ExtraColorEnum extends ColorEnum {
|
* public final class ExtraColorEnum extends ColorEnum {
|
||||||
* // NOTE: Color enum declared above is final, change that to get this
|
* // NOTE: Color enum declared above is final, change that to get this
|
||||||
* // example to compile.
|
* // example to compile.
|
||||||
* public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
|
* public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
|
||||||
|
@ -159,24 +162,31 @@ import org.apache.commons.lang.StringUtils;
|
||||||
*
|
*
|
||||||
* <h4>Functional Enums</h4>
|
* <h4>Functional Enums</h4>
|
||||||
*
|
*
|
||||||
* <p>The enums can have functionality by using anonymous inner classes
|
* <p>The enums can have functionality by defining subclasses and
|
||||||
* [Effective Java, Bloch01]:</p>
|
* changing the <code>super()</code> call:</p>
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* public abstract class OperationEnum extends Enum {
|
* public static final OperationEnum PLUS = new PlusOperation();
|
||||||
* public static final OperationEnum PLUS = new OperationEnum("Plus") {
|
* private static final class PlusOperation extends OperationEnum {
|
||||||
* public double eval(double a, double b) {
|
* private PlusOperation() {
|
||||||
|
* super("Plus");
|
||||||
|
* }
|
||||||
|
* public int eval(int a, int b) {
|
||||||
* return (a + b);
|
* return (a + b);
|
||||||
* }
|
* }
|
||||||
* };
|
* }
|
||||||
* public static final OperationEnum MINUS = new OperationEnum("Minus") {
|
* public static final OperationEnum MINUS = new MinusOperation();
|
||||||
* public double eval(double a, double b) {
|
* private static final class MinusOperation extends OperationEnum {
|
||||||
|
* private MinusOperation() {
|
||||||
|
* super("Minus");
|
||||||
|
* }
|
||||||
|
* public int eval(int a, int b) {
|
||||||
* return (a - b);
|
* return (a - b);
|
||||||
* }
|
* }
|
||||||
* };
|
* }
|
||||||
*
|
*
|
||||||
* private OperationEnum(String color) {
|
* private OperationEnum(String color) {
|
||||||
* super(color);
|
* super(color, OperationEnum.class); // NOTE: super() changed!
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* public abstract double eval(double a, double b);
|
* public abstract double eval(double a, double b);
|
||||||
|
@ -198,18 +208,20 @@ import org.apache.commons.lang.StringUtils;
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
|
* <p>The code above will work on JDK 1.2. If JDK1.3 and later is used,
|
||||||
|
* the subclasses may be defined as anonymous.</p>
|
||||||
*
|
*
|
||||||
* @author Apache Avalon project
|
* @author Apache Avalon project
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @author Chris Webb
|
* @author Chris Webb
|
||||||
* @author Mike Bowler
|
* @author Mike Bowler
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
* @version $Id: Enum.java,v 1.17 2003/07/30 23:17:23 scolebourne Exp $
|
* @version $Id: Enum.java,v 1.18 2003/08/04 23:52:27 scolebourne Exp $
|
||||||
*/
|
*/
|
||||||
public abstract class Enum implements Comparable, Serializable {
|
public abstract class Enum implements Comparable, Serializable {
|
||||||
|
|
||||||
/** Lang version 1.0.1 serial compatability */
|
/** Lang version 1.0.1 serial compatability */
|
||||||
static final long serialVersionUID = -487045951170455942L;
|
private static final long serialVersionUID = -487045951170455942L;
|
||||||
|
|
||||||
// After discussion, the default size for HashMaps is used, as the
|
// After discussion, the default size for HashMaps is used, as the
|
||||||
// sizing algorithm changes across the JDK versions
|
// sizing algorithm changes across the JDK versions
|
||||||
|
@ -225,6 +237,10 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
* The string representation of the Enum.
|
* The string representation of the Enum.
|
||||||
*/
|
*/
|
||||||
private final String iName;
|
private final String iName;
|
||||||
|
/**
|
||||||
|
* The Enum class.
|
||||||
|
*/
|
||||||
|
private final Class iEnumClass;
|
||||||
/**
|
/**
|
||||||
* The hashcode representation of the Enum.
|
* The hashcode representation of the Enum.
|
||||||
*/
|
*/
|
||||||
|
@ -264,15 +280,53 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
*/
|
*/
|
||||||
protected Enum(String name) {
|
protected Enum(String name) {
|
||||||
super();
|
super();
|
||||||
|
init(name, getClass());
|
||||||
|
iName = name;
|
||||||
|
iEnumClass = getClass();
|
||||||
|
iHashCode = 7 + iEnumClass.hashCode() + 3 * name.hashCode();
|
||||||
|
// cannot create toString here as subclasses may want to include other data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructor to add a new named item to the enumeration.</p>
|
||||||
|
*
|
||||||
|
* <p>This constructor is used when a subclass wants to allow further
|
||||||
|
* subclasses to add values to the enumeration. The class specifies
|
||||||
|
* which class they are all to be tied to.</p>
|
||||||
|
*
|
||||||
|
* @param name the name of the enum object,
|
||||||
|
* must not be empty or <code>null</code>
|
||||||
|
* @param enumClass the enum class,
|
||||||
|
* must not be null and must be this class or a superclass
|
||||||
|
* @throws IllegalArgumentException if the name is <code>null</code>
|
||||||
|
* or an empty string
|
||||||
|
* @throws IllegalArgumentException if the enumClass is <code>null</code>
|
||||||
|
* or invalid
|
||||||
|
*/
|
||||||
|
protected Enum(String name, Class enumClass) {
|
||||||
|
super();
|
||||||
|
init(name, enumClass);
|
||||||
|
iName = name;
|
||||||
|
iEnumClass = enumClass;
|
||||||
|
iHashCode = 7 + enumClass.hashCode() + 3 * name.hashCode();
|
||||||
|
// cannot create toString here as subclasses may want to include other data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the enumeration.
|
||||||
|
*
|
||||||
|
* @param name the enum name
|
||||||
|
* @param enumClass the enum class
|
||||||
|
* @throws IllegalArgumentException if the name is null or empty
|
||||||
|
* @throws IllegalArgumentException if the enumClass is null or invalid
|
||||||
|
*/
|
||||||
|
private void init(String name, Class enumClass) {
|
||||||
if (StringUtils.isEmpty(name)) {
|
if (StringUtils.isEmpty(name)) {
|
||||||
throw new IllegalArgumentException("The Enum name must not be empty or null");
|
throw new IllegalArgumentException("The Enum name must not be empty or null");
|
||||||
}
|
}
|
||||||
iName = name;
|
|
||||||
Class enumClass = Enum.getEnumClass(getClass());
|
|
||||||
Entry entry = (Entry) cEnumClasses.get(enumClass);
|
Entry entry = (Entry) cEnumClasses.get(enumClass);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
entry = createEntry(getClass());
|
entry = createEntry(enumClass);
|
||||||
cEnumClasses.put(enumClass, entry);
|
cEnumClasses.put(enumClass, entry);
|
||||||
}
|
}
|
||||||
if (entry.map.containsKey(name)) {
|
if (entry.map.containsKey(name)) {
|
||||||
|
@ -280,9 +334,6 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
}
|
}
|
||||||
entry.map.put(name, this);
|
entry.map.put(name, this);
|
||||||
entry.list.add(this);
|
entry.list.add(this);
|
||||||
|
|
||||||
iHashCode = 7 + enumClass.hashCode() + 3 * name.hashCode();
|
|
||||||
// cannot create toString here as subclasses may want to include other data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,7 +343,7 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
* @return the resolved object
|
* @return the resolved object
|
||||||
*/
|
*/
|
||||||
protected Object readResolve() {
|
protected Object readResolve() {
|
||||||
Entry entry = (Entry) cEnumClasses.get(Enum.getEnumClass(getClass()));
|
Entry entry = (Entry) cEnumClasses.get(iEnumClass);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -422,29 +473,6 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Convert a class to the actual common enum class.</p>
|
|
||||||
*
|
|
||||||
* <p>This accounts for anonymous inner classes.</p>
|
|
||||||
*
|
|
||||||
* @param cls the class to get the name for
|
|
||||||
* @return the class name
|
|
||||||
*/
|
|
||||||
protected static Class getEnumClass(Class cls) {
|
|
||||||
String className = cls.getName();
|
|
||||||
int index = className.lastIndexOf('$');
|
|
||||||
if (index > -1) {
|
|
||||||
// is it an anonymous inner class?
|
|
||||||
String inner = className.substring(index + 1);
|
|
||||||
if (inner.length() > 0 &&
|
|
||||||
inner.charAt(0) >= '0' &&
|
|
||||||
inner.charAt(0) < '9') {
|
|
||||||
return cls.getSuperclass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cls;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* <p>Retrieve the name of this Enum item, set in the constructor.</p>
|
* <p>Retrieve the name of this Enum item, set in the constructor.</p>
|
||||||
|
@ -455,6 +483,18 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
return iName;
|
return iName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Retrieves the Class of this Enum item, set in the constructor.</p>
|
||||||
|
*
|
||||||
|
* <p>This is normally the same as <code>getClass()</code>, but for
|
||||||
|
* advanced Enums may be different.</p>
|
||||||
|
*
|
||||||
|
* @return the <code>String</code> name of this Enum item
|
||||||
|
*/
|
||||||
|
public final Class getEnumClass() {
|
||||||
|
return iEnumClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Tests for equality.</p>
|
* <p>Tests for equality.</p>
|
||||||
*
|
*
|
||||||
|
@ -473,7 +513,7 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
} else if (other.getClass() == this.getClass()) {
|
} else if (other.getClass() == this.getClass()) {
|
||||||
// shouldn't happen, but...
|
// shouldn't happen, but...
|
||||||
return iName.equals(((Enum) other).iName);
|
return iName.equals(((Enum) other).iName);
|
||||||
} else if (getEnumClass(other.getClass()).getName().equals(getEnumClass(this.getClass()).getName())) {
|
} else if (((Enum) other).iEnumClass.getName().equals(iEnumClass.getName())) {
|
||||||
// different classloaders
|
// different classloaders
|
||||||
try {
|
try {
|
||||||
// try to avoid reflection
|
// try to avoid reflection
|
||||||
|
@ -537,8 +577,7 @@ public abstract class Enum implements Comparable, Serializable {
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (iToString == null) {
|
if (iToString == null) {
|
||||||
Class cls = Enum.getEnumClass(getClass());
|
String shortName = ClassUtils.getShortClassName(iEnumClass);
|
||||||
String shortName = ClassUtils.getShortClassName(cls);
|
|
||||||
iToString = shortName + "[" + getName() + "]";
|
iToString = shortName + "[" + getName() + "]";
|
||||||
}
|
}
|
||||||
return iToString;
|
return iToString;
|
||||||
|
|
|
@ -133,12 +133,12 @@ import org.apache.commons.lang.ClassUtils;
|
||||||
* @author Apache Avalon project
|
* @author Apache Avalon project
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
* @version $Id: ValuedEnum.java,v 1.10 2003/07/30 23:17:23 scolebourne Exp $
|
* @version $Id: ValuedEnum.java,v 1.11 2003/08/04 23:52:27 scolebourne Exp $
|
||||||
*/
|
*/
|
||||||
public abstract class ValuedEnum extends Enum {
|
public abstract class ValuedEnum extends Enum {
|
||||||
|
|
||||||
/** Lang version 1.0.1 serial compatability */
|
/** Lang version 1.0.1 serial compatability */
|
||||||
static final long serialVersionUID = -7129650521543789085L;
|
private static final long serialVersionUID = -7129650521543789085L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value contained in enum.
|
* The value contained in enum.
|
||||||
|
@ -148,14 +148,26 @@ public abstract class ValuedEnum extends Enum {
|
||||||
/**
|
/**
|
||||||
* Constructor for enum item.
|
* Constructor for enum item.
|
||||||
*
|
*
|
||||||
* @param name the name of enum item.
|
* @param name the name of enum item
|
||||||
* @param value the value of enum item.
|
* @param value the value of enum item
|
||||||
*/
|
*/
|
||||||
protected ValuedEnum(String name, int value) {
|
protected ValuedEnum(String name, int value) {
|
||||||
super(name);
|
super(name);
|
||||||
iValue = value;
|
iValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for enum item.
|
||||||
|
*
|
||||||
|
* @param name the name of enum item
|
||||||
|
* @param enumClass the enum class
|
||||||
|
* @param value the value of enum item
|
||||||
|
*/
|
||||||
|
protected ValuedEnum(String name, Class enumClass, int value) {
|
||||||
|
super(name, enumClass);
|
||||||
|
iValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Gets an <code>Enum</code> object by class and value.</p>
|
* <p>Gets an <code>Enum</code> object by class and value.</p>
|
||||||
*
|
*
|
||||||
|
@ -217,8 +229,7 @@ public abstract class ValuedEnum extends Enum {
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (iToString == null) {
|
if (iToString == null) {
|
||||||
Class cls = Enum.getEnumClass(getClass());
|
String shortName = ClassUtils.getShortClassName(getEnumClass());
|
||||||
String shortName = ClassUtils.getShortClassName(cls);
|
|
||||||
iToString = shortName + "[" + getName() + "=" + getValue() + "]";
|
iToString = shortName + "[" + getName() + "=" + getValue() + "]";
|
||||||
}
|
}
|
||||||
return iToString;
|
return iToString;
|
||||||
|
|
|
@ -61,27 +61,42 @@ import java.util.Map;
|
||||||
* Operator enumeration.
|
* Operator enumeration.
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @version $Id: OperationEnum.java,v 1.3 2003/08/02 18:38:36 scolebourne Exp $
|
* @version $Id: OperationEnum.java,v 1.4 2003/08/04 23:52:27 scolebourne Exp $
|
||||||
*/
|
*/
|
||||||
public abstract class OperationEnum extends Enum {
|
public abstract class OperationEnum extends Enum {
|
||||||
public static final OperationEnum PLUS;
|
// This syntax works for JDK 1.3 and upwards:
|
||||||
public static final OperationEnum MINUS;
|
// public static final OperationEnum PLUS = new OperationEnum("Plus") {
|
||||||
static {
|
// public int eval(int a, int b) {
|
||||||
// Get around JDK Linux bug
|
// return (a + b);
|
||||||
PLUS = new OperationEnum("Plus") {
|
// }
|
||||||
public int eval(int a, int b) {
|
// };
|
||||||
return (a + b);
|
// public static final OperationEnum MINUS = new OperationEnum("Minus") {
|
||||||
}
|
// public int eval(int a, int b) {
|
||||||
};
|
// return (a - b);
|
||||||
MINUS = new OperationEnum("Minus") {
|
// }
|
||||||
public int eval(int a, int b) {
|
// };
|
||||||
return (a - b);
|
// This syntax works for JDK 1.2 and upwards:
|
||||||
}
|
public static final OperationEnum PLUS = new PlusOperation();
|
||||||
};
|
private static class PlusOperation extends OperationEnum {
|
||||||
|
private PlusOperation() {
|
||||||
|
super("Plus");
|
||||||
|
}
|
||||||
|
public int eval(int a, int b) {
|
||||||
|
return (a + b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static final OperationEnum MINUS = new MinusOperation();
|
||||||
|
private static class MinusOperation extends OperationEnum {
|
||||||
|
private MinusOperation() {
|
||||||
|
super("Minus");
|
||||||
|
}
|
||||||
|
public int eval(int a, int b) {
|
||||||
|
return (a - b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private OperationEnum(String name) {
|
private OperationEnum(String name) {
|
||||||
super(name);
|
super(name, OperationEnum.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int eval(int a, int b);
|
public abstract int eval(int a, int b);
|
||||||
|
|
Loading…
Reference in New Issue