xerial / sqlite-jdbc

SQLite JDBC Driver
Apache License 2.0
2.86k stars 619 forks source link

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

Closed ianhash closed 5 months ago

ianhash commented 5 months ago

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):

Additional context

gotson commented 5 months ago

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

ianhash commented 5 months ago

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" };
    }
gotson commented 5 months ago

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

ianhash commented 5 months ago

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;
        }
    }
}
ianhash commented 5 months ago

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

gotson commented 5 months ago

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.

ianhash commented 5 months ago

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.

github-actions[bot] commented 3 months ago

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