diff --git a/src/java/org/apache/commons/lang/enum/Enum.java b/src/java/org/apache/commons/lang/enum/Enum.java index 9daf58494..7a6af5522 100644 --- a/src/java/org/apache/commons/lang/enum/Enum.java +++ b/src/java/org/apache/commons/lang/enum/Enum.java @@ -111,12 +111,52 @@ import java.util.Map; * Unfortunately, Java restrictions require these to be coded as shown in each subclass. * An alternative choice is to use the {@link EnumUtils} class. *
+ * The enums can have functionality by using anonymous inner classes + * [Effective Java, Bloch01]: + *
+ * public abstract class OperationEnum extends Enum { + * public static final OperationEnum PLUS = new OperationEnum("Plus") { + * public double eval(double a, double b) { + * return (a + b); + * } + * }; + * public static final OperationEnum MINUS = new OperationEnum("Minus") { + * public double eval(double a, double b) { + * return (a - b); + * } + * }; + * + * private OperationEnum(String color) { + * super(color); + * } + * + * public abstract double eval(double a, double b); + * + * public static OperationEnum getEnum(String name) { + * return (OperationEnum) getEnum(OperationEnum.class, name); + * } + * + * public static Map getEnumMap() { + * return getEnumMap(OperationEnum.class); + * } + * + * public static List getEnumList() { + * return getEnumList(OperationEnum.class); + * } + * + * public static Iterator iterator() { + * return iterator(OperationEnum.class); + * } + * } + *+ *
* NOTE: This class originated in the Jakarta Avalon project. *
* * @author Stephen Colebourne + * @author Chris Webb * @since 1.0 - * @version $Id: Enum.java,v 1.5 2002/12/23 00:17:06 scolebourne Exp $ + * @version $Id: Enum.java,v 1.6 2002/12/31 22:39:39 scolebourne Exp $ */ public abstract class Enum implements Comparable, Serializable { /** @@ -160,10 +200,11 @@ public abstract class Enum implements Comparable, Serializable { throw new IllegalArgumentException("The Enum name must not be empty"); } iName = name; - Entry entry = (Entry) cEnumClasses.get(getClass().getName()); + String className = Enum.getEnumClassName(getClass()); + Entry entry = (Entry) cEnumClasses.get(className); if (entry == null) { entry = new Entry(); - cEnumClasses.put(getClass().getName(), entry); + cEnumClasses.put(className, entry); } if (entry.map.containsKey(name)) { throw new IllegalArgumentException("The Enum name must be unique, '" + name + "' has already been added"); @@ -178,22 +219,25 @@ public abstract class Enum implements Comparable, Serializable { * @return the resolved object */ protected Object readResolve() { - return Enum.getEnum(getClass(), getName()); + Entry entry = (Entry) cEnumClasses.get(Enum.getEnumClassName(getClass())); + if (entry == null) { + return null; + } + return (Enum) entry.map.get(getName()); } + + //-------------------------------------------------------------------------------- /** * Gets an Enum object by class and name. * - * @param enumClass the class of the Enum to get + * @param enumClass the class of the Enum to get, must not be null * @param name the name of the Enum to get, may be null * @return the enum object, or null if the enum does not exist * @throws IllegalArgumentException if the enum class is null */ protected static Enum getEnum(Class enumClass, String name) { - if (enumClass == null) { - throw new IllegalArgumentException("The Enum Class must not be null"); - } - Entry entry = (Entry) cEnumClasses.get(enumClass.getName()); + Entry entry = getEntry(enumClass); if (entry == null) { return null; } @@ -204,19 +248,13 @@ public abstract class Enum implements Comparable, Serializable { * Gets the Map of Enum objects by name using the Enum class. * If the requested class has no enum objects an empty Map is returned. * - * @param enumClass the class of the Enum to get + * @param enumClass the class of the Enum to get, must not be null * @return the enum object Map * @throws IllegalArgumentException if the enum class is null * @throws IllegalArgumentException if the enum class is not a subclass of Enum */ protected static Map getEnumMap(Class enumClass) { - if (enumClass == null) { - throw new IllegalArgumentException("The Enum Class must not be null"); - } - if (Enum.class.isAssignableFrom(enumClass) == false) { - throw new IllegalArgumentException("The Class must be a subclass of Enum"); - } - Entry entry = (Entry) cEnumClasses.get(enumClass.getName()); + Entry entry = getEntry(enumClass); if (entry == null) { return EMPTY_MAP; } @@ -228,19 +266,13 @@ public abstract class Enum implements Comparable, Serializable { * The list is in the order that the objects were created (source code order). * If the requested class has no enum objects an empty List is returned. * - * @param enumClass the class of the Enum to get + * @param enumClass the class of the Enum to get, must not be null * @return the enum object Map * @throws IllegalArgumentException if the enum class is null * @throws IllegalArgumentException if the enum class is not a subclass of Enum */ protected static List getEnumList(Class enumClass) { - if (enumClass == null) { - throw new IllegalArgumentException("The Enum Class must not be null"); - } - if (Enum.class.isAssignableFrom(enumClass) == false) { - throw new IllegalArgumentException("The Class must be a subclass of Enum"); - } - Entry entry = (Entry) cEnumClasses.get(enumClass.getName()); + Entry entry = getEntry(enumClass); if (entry == null) { return Collections.EMPTY_LIST; } @@ -252,7 +284,7 @@ public abstract class Enum implements Comparable, Serializable { * The iterator is in the order that the objects were created (source code order). * If the requested class has no enum objects an empty Iterator is returned. * - * @param enumClass the class of the Enum to get + * @param enumClass the class of the Enum to get, must not be null * @return an iterator of the Enum objects * @throws IllegalArgumentException if the enum class is null * @throws IllegalArgumentException if the enum class is not a subclass of Enum @@ -261,6 +293,47 @@ public abstract class Enum implements Comparable, Serializable { return Enum.getEnumList(enumClass).iterator(); } + /** + * Gets an entry from the map of Enums. + * + * @param enumClass the class of the Enum to get + * @return the enum entry + */ + private static Entry getEntry(Class enumClass) { + if (enumClass == null) { + throw new IllegalArgumentException("The Enum Class must not be null"); + } + if (Enum.class.isAssignableFrom(enumClass) == false) { + throw new IllegalArgumentException("The Class must be a subclass of Enum"); + } + Entry entry = (Entry) cEnumClasses.get(enumClass.getName()); + return entry; + } + + /** + * Convert a class to a class name accounting for inner classes. + * + * @param cls the class to get the name for + * @return the class name + */ + protected static String getEnumClassName(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') { + // Strip off anonymous inner class reference. + className = className.substring(0, index); + } + } + return className; + } + + //-------------------------------------------------------------------------------- + /** * Retrieve the name of this Enum item, set in the constructor. * @@ -343,7 +416,7 @@ public abstract class Enum implements Comparable, Serializable { * the type name. */ public String toString() { - String shortName = getClass().getName(); + String shortName = Enum.getEnumClassName(getClass()); int pos = shortName.lastIndexOf('.'); if (pos != -1) { shortName = shortName.substring(pos + 1); diff --git a/src/java/org/apache/commons/lang/enum/ValuedEnum.java b/src/java/org/apache/commons/lang/enum/ValuedEnum.java index 6abf6109f..ae04df870 100644 --- a/src/java/org/apache/commons/lang/enum/ValuedEnum.java +++ b/src/java/org/apache/commons/lang/enum/ValuedEnum.java @@ -130,7 +130,7 @@ import java.util.List; * * @author Stephen Colebourne * @since 1.0 - * @version $Id: ValuedEnum.java,v 1.3 2002/12/23 00:17:06 scolebourne Exp $ + * @version $Id: ValuedEnum.java,v 1.4 2002/12/31 22:39:39 scolebourne Exp $ */ public abstract class ValuedEnum extends Enum { /** @@ -204,7 +204,7 @@ public abstract class ValuedEnum extends Enum { * stripped from the type name. */ public String toString() { - String shortName = getClass().getName(); + String shortName = Enum.getEnumClassName(getClass()); int pos = shortName.lastIndexOf('.'); if (pos != -1) { shortName = shortName.substring(pos + 1); diff --git a/src/test/org/apache/commons/lang/enum/EnumTest.java b/src/test/org/apache/commons/lang/enum/EnumTest.java index 61a8f114e..d33514c24 100644 --- a/src/test/org/apache/commons/lang/enum/EnumTest.java +++ b/src/test/org/apache/commons/lang/enum/EnumTest.java @@ -65,8 +65,8 @@ import org.apache.commons.lang.SerializationUtils; /** * Test cases for the {@link Enum} class. * - * @author Stephen Colebourne - * @version $Id: EnumTest.java,v 1.4 2002/11/06 19:14:43 bayard Exp $ + * @author Stephen Colebourne + * @version $Id: EnumTest.java,v 1.5 2002/12/31 22:39:39 scolebourne Exp $ */ public final class EnumTest extends TestCase { @@ -182,4 +182,46 @@ public final class EnumTest extends TestCase { } } + public void testOperationGet() { + assertSame(OperationEnum.PLUS, OperationEnum.getEnum("Plus")); + assertSame(OperationEnum.MINUS, OperationEnum.getEnum("Minus")); + assertSame(null, OperationEnum.getEnum("Pink")); + } + + public void testOperationSerialization() { + assertSame(OperationEnum.PLUS, SerializationUtils.clone(OperationEnum.PLUS)); + assertSame(OperationEnum.MINUS, SerializationUtils.clone(OperationEnum.MINUS)); + } + + public void testOperationToString() { + assertEquals("OperationEnum[Plus]", OperationEnum.PLUS.toString()); + } + + public void testOperationList() { + List list = OperationEnum.getEnumList(); + assertNotNull(list); + assertEquals(2, list.size()); + assertEquals(list.size(), OperationEnum.getEnumMap().keySet().size()); + + Iterator it = list.iterator(); + assertSame(OperationEnum.PLUS, it.next()); + assertSame(OperationEnum.MINUS, it.next()); + } + + public void testOperationMap() { + Map map = OperationEnum.getEnumMap(); + assertNotNull(map); + assertEquals(map.keySet().size(), OperationEnum.getEnumList().size()); + + assertTrue(map.containsValue(OperationEnum.PLUS)); + assertTrue(map.containsValue(OperationEnum.MINUS)); + assertSame(OperationEnum.PLUS, map.get("Plus")); + assertSame(OperationEnum.MINUS, map.get("Minus")); + } + + public void testOperationCalculation() { + assertEquals(3, OperationEnum.PLUS.eval(1, 2)); + assertEquals(-1, OperationEnum.MINUS.eval(1, 2)); + } + } diff --git a/src/test/org/apache/commons/lang/enum/OperationEnum.java b/src/test/org/apache/commons/lang/enum/OperationEnum.java new file mode 100644 index 000000000..23bfcbf4d --- /dev/null +++ b/src/test/org/apache/commons/lang/enum/OperationEnum.java @@ -0,0 +1,98 @@ +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + *