Getting java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver exception

廉价感情. 提交于 2021-02-16 09:15:43

问题


I am seeing some weird behavior when attempting to access a database using JDBC drivers. Here's the code fragment:

LOGGER.debug("driver is " + driver);
try {
    Class.forName(driver);
    LOGGER.debug("got driver");
} catch (Throwable t) {
    LOGGER.debug("throwable getting driver " + driver);
    t.printStackTrace(System.out);
    throw t;
}

When I run this, here's what I see in the stack trace.

08:20:00.417 [main] DEBUG - driver is com.sybase.jdbc4.jdbc.SybDriver
08:20:00.604 [main] DEBUG - throwable getting driver com.sybase.jdbc4.jdbc.SybDriver
java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
        at com.sybase.jdbc4.jdbc.SybDriver.registerWithDriverManager(Unknown Source)
        at com.sybase.jdbc4.jdbc.SybDriver.<init>(Unknown Source)
        at com.sybase.jdbc4.jdbc.SybDriver.<clinit>(Unknown Source)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:315)
        ... my code

So I can see that the driver name that I am trying to get is com.sybase.jdbc4.jdbc.SybDriver which is correct, but for some reason, the DriverManager is looking for oracle.jdbc.OracleDriver.

What is going on? This code has been working well for years, and the only other relevant information I can think of is that I have recently upgraded the JDK on this machine to Open JDK 11.

>java -version
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)

回答1:


This is not a complete answer, but it seems to be a class loading problem in combination with automatic driver loading.

When you explicitly use Class.forName to load a JDBC driver, the driver should register itself with java.sql.DriverManager.

Looking at the stack trace, specifically:

    at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
    at com.sybase.jdbc4.jdbc.SybDriver.registerWithDriverManager(Unknown Source)
    at com.sybase.jdbc4.jdbc.SybDriver.<init>(Unknown Source)
    at com.sybase.jdbc4.jdbc.SybDriver.<clinit>(Unknown Source)
    at java.base/java.lang.Class.forName0(Native Method)

The Sybase driver incorrectly checks currently registered drivers (using DriverManager.getDrivers) before (?) registering itself. And even worse, it does this from the driver constructor instead of a static initializer, which could potentially lead to a driver loading deadlock. A proper behaving driver should call DriverManager.registerDriver from a static initializer as specified in JDBC 4.3 section 9.2:

JDBC drivers must implement the Driver interface, and the implementation must contain a static initializer that will be called when the driver is loaded. This initializer registers a new instance of itself with the DriverManager, as shown in CODE EXAMPLE 9-1.

public class AcmeJdbcDriver implements java.sql.Driver {
    static {
        java.sql.DriverManager.registerDriver(new AcmeJdbcDriver());
    }
    ... 
} 

CODE EXAMPLE 9-1 Example static initializer for a driver implementing java.sql.Driver

When a Driver implementation is loaded, the static initializer will automatically register an instance of the driver.

Because DriverManager.getDrivers is called, it will automatically load drivers on the classpath in META-INF/service/java.sql.Driver files (and those in the system property jdbc.drivers).

It looks like the Oracle JDBC driver was discovered and loaded this way, but then a check if the driver is available in the current class loader in isDriverAllowed fails with a NoClassDefFoundError (the check catches exceptions, but not errors, and maybe it should).

As a workaround, you should either remove the Oracle JDBC driver from your class path, or find out why it is not available in the current class loader.

As further diagnosis, try to call DriverManager.getDrivers(), Class.forName("oracle.jdbc.Driver) or even new oracle.jdbc.Driver() in your code and see what happens.

You may also want to check the version of your Sybase driver, and if there is a newer version that doesn't do this check, although that may simply cause the error to occur elsewhere in your code.




回答2:


So I did some further investigation as follows. I wrote a minimal complete example:

import java.sql.*;
import java.util.*;

public class TestDrivers {

    public static void main(String[] args) {
        try {
            Enumeration<Driver> driverEnumeration = DriverManager.getDrivers();
            while (driverEnumeration.hasMoreElements()) {
                Driver driver = driverEnumeration.nextElement();
                System.out.println("driver is " + driver.getClass().getName());
            }
        } catch (Throwable t) {
            System.out.println("throwable getting drivers");
            t.printStackTrace(System.out);
            throw t;
        }
    }
}

I then ran this example with four different classpaths with the following results:

  1. No driver JAR files: success, no drivers listed
  2. Driver JAR files: jconn4.jar;jtds-1.3.1.jar;ojdbc6-11.1.0.6.0.jar: failure with java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
  3. Driver JAR files: jtds-1.3.1.jar;ojdbc6-11.1.0.6.0.jar: success with jTDS and Oracle drivers listed
  4. Driver JAR files: jconn4.jar;jtds-1.3.1.jar: success with jTDS and Sybase drivers listed

So there is some weird interaction going on if both Oracle and Sybase JDBC drivers are present. I also tried the Oracle ojdbc7.jar and ojdbc8.jar files with essentially the same results. Here's the full stacktrace:

java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
        at com.javamarket.drivers.TestDrivers.main(TestDrivers.java:10)
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class oracle.jdbc.OracleDriver
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:555)
        at java.sql/java.sql.DriverManager.isDriverAllowed(DriverManager.java:547)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:449)
        at java.sql/java.sql.DriverManager.getDrivers(DriverManager.java:426)
        at com.javamarket.drivers.TestDrivers.main(TestDrivers.java:10)

Finally, I tried this on a different machine running JDK 8 and all four classpath variations run successfully.



来源:https://stackoverflow.com/questions/54960627/getting-java-lang-noclassdeffounderror-could-not-initialize-class-oracle-jdbc-o

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!