views:

30

answers:

2

I encountered strange behavior of enum type loaded by different class loader. In common library I have enum definition (similar to the following):

enum MyEnumType { VAL_1, VAL_2, VAL_3 };

I have first application which creates following map and registers it as some kind of global in the system (the registration code is only symbolic for simplicity):

final Map<MyEnumType, String> map = new EnumMap<MyEnumType, String>(MyEnumType.class);
map.put(MyEnumType.VAL_1, "value 1");
map.put(MyEnumType.VAL_2, "value 2");
map.put(MyEnumType.VAL_3, "value 3");
GLOBAL_SYSTEM_MAP = Collections.unmodifiableMap(map);

The second application (with different class loader) performs following operation:

String value = GLOBAL_SYSTEM_MAP.get(MyEnumType.VAL_1);

and receives null value. I checked using debugger that the GLOBAL_SYSTEM_MAP was correct, contained appropriate values, yet get() method still didn't return any correct value.

I suspect that the reason may be connected with different class loaders used by both applications to load MyEnumType type. But on the other hand, the enum's equals() method is probably prepared for such a case, isn't it? So, maybe the EnumMap.get() implementation uses == instead of equals()? (but I rather doubt that) I also tried replace EnumMap by HashMap but this didn't solve the problem either.

+2  A: 

EnumMap checks the actual class of the key you pass in against the class of the enum it was created with. If they are different, get will return null. The class will be different since you are loading the MyEnum class twice with different classloaders.

The fix is to arrange for both applications use a shared instance of the MyEnum class.

mdma
+1  A: 

enum values loaded by different class loader should neither be == or equals. You should generally get some kind of error if treating different classes with the same name from different class loaders as the same. Is the type of GLOBAL_SYSTEM_MAP Map<MyEnumType,String> or Map<?,String> (or similar)?

One possible reason for an error to be hidden is that some class loaders do not delegate to their parent first (IIRC, breaks the Java SE spec, recommended by the EE specs). This causes all manner of problems.

Tom Hawtin - tackline