1

I am trying to understand JDBC internals, specifically, how is my JDBC driver being loaded if 1. I am not using Class.forName() 2. Checking for the jdbc.driver system property returns null.

I've tried checking my class path and printing the full list of system properties to the console for inspection as per https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html#registerDriver-java.sql.Driver- and https://db.apache.org/derby/docs/10.4/devguide/cdevdvlp40653.html

Below is the DBConnection constructor from DBConnection class

    `public DBConnection() {
        try {
            this.conn = DriverManager.getConnection(JDBC_URL);
            if (this.conn != null) {
                System.out.println("Connection successful");
            }
        } catch(SQLException sqlex) {
            System.out.println("Connection failed");
        }
    }`
Below is main()

    public static void main(String[] args) {

        DBConnection dbTest = new DBConnection();

        String sysPropsString = System.getProperties().toString();
        String[] propsArr = sysPropsString.split(",");

        for(String property : propsArr) {
            if (property.contains("class") && property.contains("path") 
                    && (property.contains("derby") || property.contains("drivers")))
                System.out.println(property);
        }
        System.out.println("***********************************");
        String sysDrivers = System.getProperty("jdbc.drivers");
        System.out.println(sysDrivers);
    }


I expected to have the derby jdbc driver printed to the console from the System.getProperty() call OR to find it somewhere on the classpath, but I see neither. How is the derby driver being loaded?

Below is the output:

Connection successful

java.class.path=/Users/aslotu/eclipse-workspace/Bullhorn/build/classes:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_cs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_de_DE.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_es.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_fr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_hu.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_it.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_ja_JP.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_ko_KR.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_pl.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_pt_BR.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_ru.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_zh_CN.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derbyLocale_zh_TW.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derby.jar


null

aslotu
  • 67
  • 7
  • As of Java 6 (JDBC 4), you have not needed `Class.forName` to load a JDBC driver. Instead, as noted in the [JDBC 4.0 and 4.1 features summary](https://docs.oracle.com/javadb/10.8.3.0/ref/rrefjdbc4_0summary.html), ***Autoloading of JDBC drivers.** In earlier versions of JDBC, applications had to manually register drivers before requesting Connections. With JDBC 4.0, applications no longer need to issue a Class.forName() on the driver name; instead, the DriverManager will find an appropriate JDBC driver when the application requests a Connection.* – Elliott Frisch Jan 10 '19 at 04:15
  • I'm not sure `Class.forName()` is required anymore for newer versions of Java. But to your question: SUGGESTION: Try loading the driver, then `ClassLoader.getSystemClassLoader();`, and printing out all the URLs from `URL[] urls = ((URLClassLoader)cl).getURLs()` – paulsm4 Jan 10 '19 at 04:15
  • See also [Technotes - JAR File Specification - Service Provider](https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Service%20Provider). – Elliott Frisch Jan 10 '19 at 04:17
  • When you print out `java.class.path` it ends with "...:/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home/db/lib/derby.jar". That looks like the Derby JDBC driver to me. Are you asking how your app *knows* to use that .jar file? – Gord Thompson Jan 10 '19 at 10:13
  • 1
    Whether or not `Class.forName` is needed in Java 6 depends on whether the driver declares `/META-INF/services/java.sql.Driver` with the right class name(s), and whether or not the driver jar is on the initial classpath or not. Automatic driver loading does not work for drivers on a context classpath (a common example is a driver placed in `WEB-INF/lib` of a WAR; those are not automatically loaded). – Mark Rotteveel Jan 10 '19 at 12:19

1 Answers1

1

derby.jar contains file META-INF/services/java.sql.Driver which register org.apache.derby.jdbc.AutoloadedDriver.

This work because DriverManager use ServiceLoader.

talex
  • 17,973
  • 3
  • 29
  • 66
  • That's not really an answer as it's highly specific to a specific driver implementation. – jwenting Jan 10 '19 at 07:35
  • @jwenting Isn't question specific to specific implementation? – talex Jan 10 '19 at 08:12
  • Not as I read it. He's using Derby as an example but nowhere mentions it in the text of the question itself. – jwenting Jan 10 '19 at 10:14
  • @jwenting I answered question how it was asked: "How is the derby driver being loaded?" – talex Jan 10 '19 at 10:17
  • @jwenting It actually works the same for all JDBC drivers, the only difference is the exact classname in `META-INF/services/java.sql.Driver`. – Mark Rotteveel Jan 10 '19 at 16:20
  • @MarkRotteveel I know. So the answer could have been better written by mentioning that rather than being specifically tailored towards a single driver. – jwenting Jan 14 '19 at 05:07