This seems like a crazy error, but Enum.valueOf(type, name)
seems to be unstable on Oracle JDK 7 SE.
The manifestation is that, on the exact same name String (I've verified this), the call to valueOf()
sometimes throws IllegalArgumentException
with the message No enum constant ...
.
My team ran this through the Eclipse debugger, and what we noticed is that in the following JDK implementation of valueOf on enum, enumConstantDirectory()
, i.e. the values()
list for an enum, sometimes seem to be missing some values. Not the entirety of all the values defined in the enum itself.
I can work around the bug by calling Enum.valueOf(enumclass.class, "XXX")
for all possible enum values on JVM startup. When I do this, it seems values()
always contains the full set.
However, if I don't do this type of initialization, sometimes Enum.valueOf()
will throw an IllegalArgumentException
.
Context: I'm seeing this problem when using XStream 1.4.4 to convert POJO objects that convert enum, but the problem doesn't seem to be inherently with XStream.
Has anyone seen this kind of error? I would love to hear about it if you have. It boggles my mind. Is this a bug in the Oracle JDK/JVM implementation?
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
Other relevant details:
We are using the org.reflections
library to scan all enums in our code at startup. During the scanning, we take the type of the enum, and call clazz.getEnumConstants()
on the Class object associated with the enum. This might be a relevant detail.
In looking and the java.lang.Class.getEnumConstants()
implementation, it seems to share the same enumConstants
shared object within the Class. I wonder if there's a problem with the implementation here.
Our enum is pretty simple, no static initialization, etc.
public enum ScreeningRuleType
{
INSERT,
CONFIRMATION,
AMOUNT,
EXISTENCE,
BAN,
SELECTION,
CUSTOM;
private long id;
private String descr;
ScreeningRuleType()
{
id = this.ordinal();
descr= this.toString().replace("_", " ");
}
}
Edit: In experimenting with this, I'm finding another manifestation. After using the System.out initialization, now instead of throwing IllegalArgumentException, the value returned by Enum.valueOf seems to be random.
This shows what I'm seeing in the Eclipse debugger. It clearly shows I'm calling valueOf() on the string "EXISTENCE" and "EXISTENCE".intern(), and clearly shows it's returning AMOUNT() instead.
I forget where I came across something similar - I suspect however that it was pre-java 7 and may have been back in the Java 4/5 days.
The issue is that the constructing of the accompanying structures that go with the enum
is only triggered the first time one of the enum
s is accessed. Unfortunately, if you call one of the methods that rely on these structures, valueOf
or EnumSet.allOf
for example before accessing one of the enum
s it generally fails catastrophically.
Sadly I refactored the code so this would not happen so I no longer have the sample to hand. I will try to reproduce the issue and get back to you.
I see here - Why the Java enum constants initialization is not complete? another occurrence of the issue with a demonstration.
Actually we found the issue. It's a face + palm moment. We corrupted the enum via reflection API's by attempting a deep (nonshallow) copy of a class containing an enum. This had the effect of wiping out all instance variables of the singleton enum itself. Thanks for all the assistance and suggestions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With