JDK-6710708 : Need a method to return whether an object is an enum.
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 6
  • Priority: P4
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2008-06-04
  • Updated: 2013-02-28
  • Resolved: 2013-02-28
Related Reports
Relates :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
The description of the method Class.isEnum() clashes with the name of the method. The name suggests it tells you whether the object for the class is an enum, but the description (accurately) gives a more complicated description of what it does. In short, if the enum value is overridden as an anonymous inner class, the isEnum() doesn't do what the name suggests. Instead, it returns false.



JUSTIFICATION :
The trouble is that the isEnum() behavior may match the method's documentation, but it doesn't match the method's name or the developer's needs. I never need to know if the instance was derived anonymously, I just need a method to tell me whether the object is an enum.

According to the evaluation of bug 6708424, "Given an arbitrary object, it will have to be poked at a bit to see if it is an enum constant." That's the trouble. It's not at all clear from the method name that we need to poke at it, so we're not likely to do so until we discover a bug in our code. Furthermore, the "poking" is identical in every case, so it should be a part of the standard implementation. Poking should only be required when we're looking for the unusual case, not when we're doing something standard -- If, when we write our code, we really need to know whether the enum is derived anonymously, we'll write code to determine this in the development phase. If we don't, we'll just call isEnum(), and we need it to do what it's name suggests.

In short, when the method name clashes with the method's docs, the result is quirky behavior and buggy code. (And I abandoned C++ to get away from quirky language behavior!)

I don't know the history of this method, but it looks like the method's description was written to conform to the original buggy implementation, rather than to the intention of the method or the needs of the developers.

Please give us a method that just tells us if something is an enum, with no irrelevant qualifications.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would like to see a new method that will return true if the object is an enum, regardless of whether or not it was created through an anonymous inner class. In the test case, I expect it to print "is enum = true" for every case.
ACTUAL -
The Class.isEnum() method returns true for enums that are instantiated directly, and false for enums that are instantiated as an anonymous inner class. In the test case, it prints isEnum = false for the "Delta" instance, derived anonymously.

This behavior is according to the method's specs, but clashes with the method's name. This results in buggy code.

---------- BEGIN SOURCE ----------
public enum EnumBug {
	Alpha(3),
	Beta(6),
	Delta(4) {
		@Override public int getValue() { return -1; }
		@Override public String toString() { return "Gamma"; }
	},
	Epsilon(9);

	private int value;

	EnumBug(int value) { this.value = value; }

	public int getValue() { return this.value;}

	public static boolean isEnumWorkaround(Class enumClass) {
		while (enumClass.isAnonymousClass()) {
			enumClass = enumClass.getSuperclass();
		}
		return enumClass.isEnum();
	}

	/** Workaround suggested by evaluator of bug 6708424. */
	public static boolean isEnumWorkaround2(Object enumCandidate) {
		if (enumCandidate instanceof Enum) {
			return ((Enum)enumCandidate).getDeclaringClass().isEnum();
		}
		return enumCandidate.getClass().isEnum();
	}

	public static void main(String[] args) {
		for (EnumBug thing : EnumBug.values()) {
			String nameString = thing + " (" + thing.name() + ")";
			String format = "%-18s isEnum = %-5b [workaround isEnum = %b] [workaound2 isEnum = %b]";
			System.out.println(String.format(
							format,
							nameString,
							thing.getClass().isEnum(),
							isEnumWorkaround(thing.getClass()),
							isEnumWorkaround2(thing)
			));
		}
	}
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
2 workarounds, both of which work:

	public static boolean isEnumWorkaround(Class enumClass) {
		while (enumClass.isAnonymousClass()) {
			enumClass = enumClass.getSuperclass();
		}
		return enumClass.isEnum();
	}

	/** Workaround suggested by evaluator of bug 6708424. */
	public static boolean isEnumWorkaround2(Object enumCandidate) {
		if (enumCandidate instanceof Enum) {
			return ((Enum)enumCandidate).getDeclaringClass().isEnum();
		}
		return enumCandidate.getClass().isEnum();
	}

Note: The fact that this can be easily worked around is beside the point. The problem with this quirky behavior is that leads to late-discovery of bugs, slowing down the development time. The workarounds don't fix that problem at all.

Comments
Closing as will not fix.
28-02-2013

EVALUATION The method Class.isEnum operates on Class objects and returns the correct answer for them; the method is *not* defined on java.lang.Object and is not intended to directly answer the question "is this object an enum constant."
10-06-2008