Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8169526

Enum switch inside enum-constructor causes internal NullPointerException

XMLWordPrintable

    • 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.

            sadayapalam Srikanth Adayapalam (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: