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]

Reply via email to