-
Bug
-
Resolution: Duplicate
-
P4
-
None
-
7, 8, 9
-
generic
-
generic
FULL PRODUCT VERSION :
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
EXTRA RELEVANT SYSTEM CONFIGURATION :
Seems to be a pure compiler (javac) issue. No further config required.
A DESCRIPTION OF THE PROBLEM :
An enum-switch inside the constructor of another enum causes a NullPointerException (which leads to a ExceptionInInitializerError) if the second enum also has a method with an enum switch to itself.
After a short analysis it has been shown that the compiler produces an inner class $1 containing enum switch tables for ALL enum switches. This tables are initialized with the values() method.
If a switch inside an enum constructor exists then ALL enum switch tables are initialized. This includes also the switch table of the current enum whose constructor is called.
The values() method, which is called by the switch table initialization, finds then a null array as the enum is not initialized as we are still in the construction of the enum.
This leads to a NullPointerException inside the switch table construction.
For further details see the comments in the test class.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile the test class and start it:
"javac EnumBug"
and then
"java EnumBug"
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No NullPointerException should occur. Eclipse compiler compiles it without this bug.
ACTUAL -
A NullPointerException occurs.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.ExceptionInInitializerError
at EnumBug$EnumA.<init>(EnumBug.java:16)
at EnumBug$EnumA.<clinit>(EnumBug.java:8)
at EnumBug.main(EnumBug.java:51)
Caused by: java.lang.NullPointerException
at EnumBug$EnumA.values(EnumBug.java:6)
at EnumBug$1.<clinit>(EnumBug.java:26)
... 3 more
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/**
* @author Stefan Czaska
*/
public class EnumBug {
public static enum EnumA {
A1(EnumB.B1),
A2(EnumB.B1),
A3(EnumB.B1);
private EnumA(EnumB enumB) {
// this switch causes that EnumA.values() is called
// but the values of EnumA are not present as we are
// inside the construction of them
switch(enumB) {
case B1: System.out.println("B1"); break;
case B2: System.out.println("B2"); break;
case B3: System.out.println("B3"); break;
}
}
public void doEnumASwitch() {
// the switch table of this switch is shared with all
// other switch tables
switch(this) {
case A1: System.out.println("A1"); break;
case A2: System.out.println("A2"); break;
case A3: System.out.println("A3"); break;
}
}
}
public static enum EnumB {
B1,B2,B3;
}
public static void main(String[] args) {
// * Access EnumA to force class initialization for EnumA.
// * Both switches share the same inner synthetic class $1.
// * In order to do the switch inside the constructor, $1
// is initialized which also initialized the switch table
// for EnumA inside $1 which uses the values() method.
// * values() performs a clone of the values array, but this
// array can not be initialized at this moment as we are
// still inside the constructor of EnumA.A1, the first value
// of EnumA.
// * This causes a NullPointerException.
// * Possible solution: Use two different switch tables. One for
// this-switches and one for all other switches.
System.out.println(EnumA.A1.toString());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use Eclipse compiler or dont use enum-switches as here reported.
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
EXTRA RELEVANT SYSTEM CONFIGURATION :
Seems to be a pure compiler (javac) issue. No further config required.
A DESCRIPTION OF THE PROBLEM :
An enum-switch inside the constructor of another enum causes a NullPointerException (which leads to a ExceptionInInitializerError) if the second enum also has a method with an enum switch to itself.
After a short analysis it has been shown that the compiler produces an inner class $1 containing enum switch tables for ALL enum switches. This tables are initialized with the values() method.
If a switch inside an enum constructor exists then ALL enum switch tables are initialized. This includes also the switch table of the current enum whose constructor is called.
The values() method, which is called by the switch table initialization, finds then a null array as the enum is not initialized as we are still in the construction of the enum.
This leads to a NullPointerException inside the switch table construction.
For further details see the comments in the test class.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
compile the test class and start it:
"javac EnumBug"
and then
"java EnumBug"
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No NullPointerException should occur. Eclipse compiler compiles it without this bug.
ACTUAL -
A NullPointerException occurs.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.ExceptionInInitializerError
at EnumBug$EnumA.<init>(EnumBug.java:16)
at EnumBug$EnumA.<clinit>(EnumBug.java:8)
at EnumBug.main(EnumBug.java:51)
Caused by: java.lang.NullPointerException
at EnumBug$EnumA.values(EnumBug.java:6)
at EnumBug$1.<clinit>(EnumBug.java:26)
... 3 more
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/**
* @author Stefan Czaska
*/
public class EnumBug {
public static enum EnumA {
A1(EnumB.B1),
A2(EnumB.B1),
A3(EnumB.B1);
private EnumA(EnumB enumB) {
// this switch causes that EnumA.values() is called
// but the values of EnumA are not present as we are
// inside the construction of them
switch(enumB) {
case B1: System.out.println("B1"); break;
case B2: System.out.println("B2"); break;
case B3: System.out.println("B3"); break;
}
}
public void doEnumASwitch() {
// the switch table of this switch is shared with all
// other switch tables
switch(this) {
case A1: System.out.println("A1"); break;
case A2: System.out.println("A2"); break;
case A3: System.out.println("A3"); break;
}
}
}
public static enum EnumB {
B1,B2,B3;
}
public static void main(String[] args) {
// * Access EnumA to force class initialization for EnumA.
// * Both switches share the same inner synthetic class $1.
// * In order to do the switch inside the constructor, $1
// is initialized which also initialized the switch table
// for EnumA inside $1 which uses the values() method.
// * values() performs a clone of the values array, but this
// array can not be initialized at this moment as we are
// still inside the constructor of EnumA.A1, the first value
// of EnumA.
// * This causes a NullPointerException.
// * Possible solution: Use two different switch tables. One for
// this-switches and one for all other switches.
System.out.println(EnumA.A1.toString());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use Eclipse compiler or dont use enum-switches as here reported.
- relates to
-
JDK-7176515 ExceptionInInitializerError for an enum with multiple switch statements
- Resolved