xerial/sqlite-jdbc

got java.lang.ExceptionInInitializerError when calling SQLiteConfig.Pragma.values()

ianhash opened this issue · 8 comments

Describe the bug
i got java.lang.ExceptionInInitializerError when calling SQLiteConfig.Pragma.values(), it seems there was an issue during the static initialization phase of the Pragma enum in the SQLiteConfig class

To Reproduce

  public static void main(String[] args) {

        SQLiteConfig.Pragma[] values = SQLiteConfig.Pragma.values();

        for (SQLiteConfig.Pragma value : values) {
            System.out.println(value);
        }
    }

sqlite-jdbc version >=3.25.2,here is 3.46.0.0

Expected behavior
just like sqlite-jdbc version <=3.23.1, it should print all SQLiteConfig.Pragma enum contants.

Logs
sqlite-jdbc version = 3.46.0.0

Exception in thread "main" java.lang.ExceptionInInitializerError
        at org.sqlite.SQLiteConfig$Pragma.<clinit>(SQLiteConfig.java:380)
        at mess.javamess.sqlite.SqliteConfigInit.main(SqliteConfigInit.java:15)
Caused by: java.lang.NullPointerException
        at org.sqlite.SQLiteConfig$Pragma.values(SQLiteConfig.java:376)
        at org.sqlite.SQLiteConfig.<clinit>(SQLiteConfig.java:357)
        ... 2 more

Environment (please complete the following information):

  • OS: MacOs m1
  • CPU architecture: arm64
  • sqlite-jdbc version >=3.25.2
  • java version: adoptopenjdk-8.jdk openjdk@11/11.0.23 openjdk 21.0.3 oracel jdk-22

Additional context

Interesting. I have no idea why this happens, any insights are welcome.

Interesting. I have no idea why this happens, any insights are welcome.

I think there is a circular dependencies in static initialization ,

SQLiteConfig.class -> SQLiteConfig static block -> SQLiteConfig.Pragma -> SQLiteConfig.OnOff -> SQLiteConfig.class

I think the private static field OnOff needs to be extracted to another class,just like this:

   static class OnOff {
        private static final String[] OnOff = new String[] { "true", "false" };
    }

i tried inlining the OnOff field and remove the field altogether, but the problem remains.

i tried inlining the OnOff field and remove the field altogether, but the problem remains.

inlining MUST BE OK,

public class Foo {

    public static final Set<String> FOO_TYPES = new HashSet<>();

    private static final String[] OnOff = new String[] { "true", "false" };

    static {
        for (Foo.FooType v : Foo.FooType.values()) {
            FOO_TYPES.add(v.name());
        }
    }

    public static enum FooType {
        A(null),
        B(OnOff),  // BAD
        // B(new String[] { "true", "false" }) ,  // GOOD
        ;

        public final String[] choices;

        FooType(String[] onOff) {
            this.choices = onOff;
        }
    }
}

BTW: My suggestion is to extract OnOff into another class。

inlining MUST BE OK,

i tested this with a unit test and it still fails. I don't see how extracting the class would be any different, if inlining the array does not work.

inlining MUST BE OK,

i tested this with a unit test and it still fails. I don't see how extracting the class would be any different, if inlining the array does not work.

The method toStringArray has same problem. this method is only called in class Pragma, so I moved it to Pragma.

please look into my pr #1124 for the details.

🎉 This issue has been resolved in 3.46.0.1 (Release Notes)