Commons Lang
  1. Commons Lang
  2. LANG-146

Enum does not support inner sub-classes

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0
    • Fix Version/s: 2.0
    • Component/s: None
    • Labels:
      None
    • Environment:

      Operating System: other
      Platform: PC

      Description

      The org.apache.commons.lang.enum.Enum class does not support the following
      construct of static inner anonymous sub-classed constants:

      public abstract class MyEnum extends Enum {
      public static final MyEnum ENUM1 = new MyEnum("enum1") {
      public String getValue()

      { return "X"; }

      };

      public static final MyEnum ENUM2 = new MyEnum("enum2") {
      public String getValue()

      { return "Y"; }

      };

      /**

      • Constructor.
        */
        protected MyEnum(String name) { super(name); }

      /**

      • Returns a value.
      • Creation date: (16/12/2002 13:25:35)
        */
        public abstract String getValue();
        }

      ENUM1 and ENUM2 are assigned anonymous inner class names 'MyEnum$0' and
      'MyEnum$1' respectively instead of the super class 'MyEnum' when added to the
      list of enumerations kept in the Enum super class via the Enum constructor.

      A simple work around is to strip the inner class descriminator off the class
      name in the Enum constructor, i.e.

      protected Enum(String name) {
      super();
      if (name == null || name.length() == 0)

      { throw new IllegalArgumentException("The Enum name must not be empty"); }

      iName = name;

      // Retrieve class name.
      String className = getClass().getName();

      // Search for inner class.
      int index = className.lastIndexOf('$');
      if (index > -1)

      { // Strip off inner class reference. className = className.substring(0, index); }

      Entry entry = (Entry) cEnumClasses.get(className);

      if (entry == null)

      { entry = new Entry(); cEnumClasses.put(className, entry); }

      if (entry.map.containsKey(name))

      { throw new IllegalArgumentException("The Enum name must be unique, '" + name + "' has already been added"); }

      entry.map.put(name, this);
      entry.list.add(this);
      }

        Activity

        Hide
        Stephen Colebourne added a comment -

        In the example given, it would seem appropriate to add an extra parameter to
        the constructor:

        public static final MyEnum ENUM1 = new MyEnum("enum1", "X");

        Does this solve the problem?

        Show
        Stephen Colebourne added a comment - In the example given, it would seem appropriate to add an extra parameter to the constructor: public static final MyEnum ENUM1 = new MyEnum("enum1", "X"); Does this solve the problem?
        Hide
        Chris Webb added a comment -

        Yes I agree if the inner sub-class method was just returning a value then
        modifying the constructor to take in the value would work because no
        sub-classing would be required. My example was probably not the best because I
        was thinking more along the lines where the static enum definition contained a
        method that encapsulated logic other than merely returning a value which would
        require sub-classing.

        Show
        Chris Webb added a comment - Yes I agree if the inner sub-class method was just returning a value then modifying the constructor to take in the value would work because no sub-classing would be required. My example was probably not the best because I was thinking more along the lines where the static enum definition contained a method that encapsulated logic other than merely returning a value which would require sub-classing.
        Hide
        Stephen Colebourne added a comment -

        Change made to support functional enums along the lines proposed here. Check
        the CVS.

        Show
        Stephen Colebourne added a comment - Change made to support functional enums along the lines proposed here. Check the CVS.
        Hide
        Chris Webb added a comment -

        Created an attachment (id=4621)
        Patch Enum class

        Show
        Chris Webb added a comment - Created an attachment (id=4621) Patch Enum class
        Hide
        Chris Webb added a comment -

        Created an attachment (id=4622)
        Enum test class

        Show
        Chris Webb added a comment - Created an attachment (id=4622) Enum test class
        Hide
        Chris Webb added a comment -

        I found a bug with my original very simplisting solution. The follwing is the
        correct algorythm to determine the actual enumeration class for a given
        enumeration object which may be defined by an inner class. I've attached the
        patched class and a test class.

        // Search for actual enumerated type. This is necessary as enumerated types might
        // be defined by inner classes. The actual enumerated type is defined as the top
        container or
        // declaring class that can be assigned to the actual class of enumeration being
        added.
        Class clazz = this.getClass();
        while (clazz.getDeclaringClass() != null &&
        clazz.getDeclaringClass().isAssignableFrom(this.getClass()))

        { clazz = clazz.getSuperclass(); }
        Show
        Chris Webb added a comment - I found a bug with my original very simplisting solution. The follwing is the correct algorythm to determine the actual enumeration class for a given enumeration object which may be defined by an inner class. I've attached the patched class and a test class. // Search for actual enumerated type. This is necessary as enumerated types might // be defined by inner classes. The actual enumerated type is defined as the top container or // declaring class that can be assigned to the actual class of enumeration being added. Class clazz = this.getClass(); while (clazz.getDeclaringClass() != null && clazz.getDeclaringClass().isAssignableFrom(this.getClass())) { clazz = clazz.getSuperclass(); }
        Hide
        Stephen Colebourne added a comment -

        Regrettably, getDeclaringClass() doesn't function correctly on my JDK141. I
        have got a version and test code on the CVS for your problem, and also to
        support hierarchical Enums now. Perhaps you could test that?
        Stephen

        Show
        Stephen Colebourne added a comment - Regrettably, getDeclaringClass() doesn't function correctly on my JDK141. I have got a version and test code on the CVS for your problem, and also to support hierarchical Enums now. Perhaps you could test that? Stephen
        Hide
        Stephen Colebourne added a comment -

        Closing as I believe fixed in CVS

        Show
        Stephen Colebourne added a comment - Closing as I believe fixed in CVS

          People

          • Assignee:
            Unassigned
            Reporter:
            Chris Webb
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development