scolebourne 2003/08/04 16:52:28
Modified: lang/src/java/org/apache/commons/lang/enum Enum.java
ValuedEnum.java
lang/src/test/org/apache/commons/lang/enum
OperationEnum.java
Log:
Rework Functional Enums to work on JDK1.2
bug 19030
Revision Changes Path
1.18 +87 -48
jakarta-commons/lang/src/java/org/apache/commons/lang/enum/Enum.java
Index: Enum.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/enum/Enum.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- Enum.java 30 Jul 2003 23:17:23 -0000 1.17
+++ Enum.java 4 Aug 2003 23:52:27 -0000 1.18
@@ -75,9 +75,12 @@
* however that a more robust type-safe class-based solution can be designed. This
* 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
- * should always be done using the equals() method, not ==. The equals() method will
- * try == first so in most cases the effect is the same.</p>
+ * <p><em>NOTE:</em>Due to the way in which Java ClassLoaders work, comparing
+ * Enum objects should always be done using <code>equals()</code>, not
<code>==</code>.
+ * 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>
*
@@ -125,7 +128,7 @@
* superclass and subclass.</p>
*
* <pre>
- * public class ExtraColorEnum extends ColorEnum {
+ * public final class ExtraColorEnum extends ColorEnum {
* // NOTE: Color enum declared above is final, change that to get this
* // example to compile.
* public static final ColorEnum YELLOW = new ExtraColorEnum("Yellow");
@@ -159,24 +162,31 @@
*
* <h4>Functional Enums</h4>
*
- * <p>The enums can have functionality by using anonymous inner classes
- * [Effective Java, Bloch01]:</p>
+ * <p>The enums can have functionality by defining subclasses and
+ * changing the <code>super()</code> call:</p>
*
* <pre>
- * public abstract class OperationEnum extends Enum {
- * public static final OperationEnum PLUS = new OperationEnum("Plus") {
- * public double eval(double a, double b) {
+ * public static final OperationEnum PLUS = new PlusOperation();
+ * private static final class PlusOperation extends OperationEnum {
+ * private PlusOperation() {
+ * super("Plus");
+ * }
+ * public int eval(int a, int b) {
* return (a + b);
* }
- * };
- * public static final OperationEnum MINUS = new OperationEnum("Minus") {
- * public double eval(double a, double b) {
+ * }
+ * public static final OperationEnum MINUS = new MinusOperation();
+ * private static final class MinusOperation extends OperationEnum {
+ * private MinusOperation() {
+ * super("Minus");
+ * }
+ * public int eval(int a, int b) {
* return (a - b);
* }
- * };
+ * }
*
* private OperationEnum(String color) {
- * super(color);
+ * super(color, OperationEnum.class); // NOTE: super() changed!
* }
*
* public abstract double eval(double a, double b);
@@ -198,6 +208,8 @@
* }
* }
* </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 Stephen Colebourne
@@ -209,7 +221,7 @@
public abstract class Enum implements Comparable, Serializable {
/** 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
// sizing algorithm changes across the JDK versions
@@ -226,6 +238,10 @@
*/
private final String iName;
/**
+ * The Enum class.
+ */
+ private final Class iEnumClass;
+ /**
* The hashcode representation of the Enum.
*/
private transient final int iHashCode;
@@ -264,15 +280,53 @@
*/
protected Enum(String name) {
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)) {
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);
if (entry == null) {
- entry = createEntry(getClass());
+ entry = createEntry(enumClass);
cEnumClasses.put(enumClass, entry);
}
if (entry.map.containsKey(name)) {
@@ -280,9 +334,6 @@
}
entry.map.put(name, 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 @@
* @return the resolved object
*/
protected Object readResolve() {
- Entry entry = (Entry) cEnumClasses.get(Enum.getEnumClass(getClass()));
+ Entry entry = (Entry) cEnumClasses.get(iEnumClass);
if (entry == null) {
return null;
}
@@ -422,37 +473,26 @@
return entry;
}
+ //-----------------------------------------------------------------------
/**
- * <p>Convert a class to the actual common enum class.</p>
- *
- * <p>This accounts for anonymous inner classes.</p>
+ * <p>Retrieve the name of this Enum item, set in the constructor.</p>
*
- * @param cls the class to get the name for
- * @return the class name
+ * @return the <code>String</code> name of this Enum item
*/
- 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;
+ public final String getName() {
+ return iName;
}
- //-----------------------------------------------------------------------
/**
- * <p>Retrieve the name of this Enum item, set in the constructor.</p>
+ * <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 String getName() {
- return iName;
+ public final Class getEnumClass() {
+ return iEnumClass;
}
/**
@@ -473,7 +513,7 @@
} else if (other.getClass() == this.getClass()) {
// shouldn't happen, but...
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
try {
// try to avoid reflection
@@ -537,8 +577,7 @@
*/
public String toString() {
if (iToString == null) {
- Class cls = Enum.getEnumClass(getClass());
- String shortName = ClassUtils.getShortClassName(cls);
+ String shortName = ClassUtils.getShortClassName(iEnumClass);
iToString = shortName + "[" + getName() + "]";
}
return iToString;
1.11 +17 -6
jakarta-commons/lang/src/java/org/apache/commons/lang/enum/ValuedEnum.java
Index: ValuedEnum.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/enum/ValuedEnum.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- ValuedEnum.java 30 Jul 2003 23:17:23 -0000 1.10
+++ ValuedEnum.java 4 Aug 2003 23:52:27 -0000 1.11
@@ -138,7 +138,7 @@
public abstract class ValuedEnum extends Enum {
/** Lang version 1.0.1 serial compatability */
- static final long serialVersionUID = -7129650521543789085L;
+ private static final long serialVersionUID = -7129650521543789085L;
/**
* The value contained in enum.
@@ -148,8 +148,8 @@
/**
* Constructor for enum item.
*
- * @param name the name of enum item.
- * @param value the value of enum item.
+ * @param name the name of enum item
+ * @param value the value of enum item
*/
protected ValuedEnum(String name, int value) {
super(name);
@@ -157,6 +157,18 @@
}
/**
+ * 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>This method loops through the list of <code>Enum</code>,
@@ -217,8 +229,7 @@
*/
public String toString() {
if (iToString == null) {
- Class cls = Enum.getEnumClass(getClass());
- String shortName = ClassUtils.getShortClassName(cls);
+ String shortName = ClassUtils.getShortClassName(getEnumClass());
iToString = shortName + "[" + getName() + "=" + getValue() + "]";
}
return iToString;
1.4 +31 -16
jakarta-commons/lang/src/test/org/apache/commons/lang/enum/OperationEnum.java
Index: OperationEnum.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/enum/OperationEnum.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- OperationEnum.java 2 Aug 2003 18:38:36 -0000 1.3
+++ OperationEnum.java 4 Aug 2003 23:52:27 -0000 1.4
@@ -64,24 +64,39 @@
* @version $Id$
*/
public abstract class OperationEnum extends Enum {
- public static final OperationEnum PLUS;
- public static final OperationEnum MINUS;
- static {
- // Get around JDK Linux bug
- PLUS = new OperationEnum("Plus") {
- 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.3 and upwards:
+// public static final OperationEnum 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);
+// }
+// };
+ // 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) {
- super(name);
+ super(name, OperationEnum.class);
}
public abstract int eval(int a, int b);
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]