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

DriverManager.getDriver fail when previous driver initialization failed

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      macOS Montery 12.6

      java version "11.0.14" 2022-01-18 LTS
      Java(TM) SE Runtime Environment 18.9 (build 11.0.14+8-LTS-263)
      Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.14+8-LTS-263, mixed mode)


      A DESCRIPTION OF THE PROBLEM :
      ## Background

      My test project run on JDK 11. Dependencies include Derby and H2 JDBC driver.
      When `DriverManager.getDriver` is called, JDBC drivers SPI loaded by ServiceLoader is in order, Derby and then H2 on my machine.

      If loading Derby driver throws exception, then H2 driver will not be loaded any more.

      Related code:
      ```
      DriverManager.ensureDriversInitialized
                          ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                          Iterator<Driver> driversIterator = loadedDrivers.iterator();
                          // ...
                          try {
                              while (driversIterator.hasNext()) {
                                  driversIterator.next();
                              }
                          } catch (Throwable t) {
                              // Do nothing
                          }
      ```
      The try catch block includes whole while loop, any `driversIterator.next()` failure will break while loop.

      I searched in bug database, there is a similar one: https://bugs.openjdk.org/browse/JDK-8190759 , but it was closed and unresolved.

      ## Reproduce steps
      Gradle dependencies:
      ```
              compile 'org.apache.derby:derby:10.16.1.1' // class file version 61.0, compile by JDK 17
              compile 'com.h2database:h2:2.2.224'
      ```

      Test code:
      ```
      public class DriverManagerTest {
          @Test
          public void testGetDriverFailedOfClassVersion() throws SQLException {
              DriverManager.getDriver("jdbc:h2:mem:test1;DATABASE_TO_UPPER=false;MODE=MySQL");
          }
      }
      ```

      Run result:
      ```
      java.sql.SQLException: No suitable driver
      at java.sql/java.sql.DriverManager.getDriver(DriverManager.java:298)
      at jdbc.DriverManagerTest.testGetDriverFailedOfClassVersion(DriverManagerTest.java:13)
      ```

      When I debug on DriverManager, the thrown exception message is:
      ```
      java.lang.UnsupportedClassVersionError: org/apache/derby/iapi/jdbc/AutoloadedDriver has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
      ```

      The reason is Derby driver is compile by JDK 17, but my local JDK is version 11.

      ## Possible solution
      Move try catch block into while loop in DriverManager.ensureDriversInitialized, e.g.
      ```
      while (driversIterator.hasNext()) {
      try {
              driversIterator.next();
      } catch (Throwable t) {
      // Do nothing
      }
      }
      ```

      ## Motivation

      Currently, when error occur, there is no any error message, just show `SQLException: No suitable driver`, it is confusing.

      If it ignore invalid driver and keep initialize other drivers, then user program still works on valid drivers. It might be robuster than before.



            lancea Lance Andersen
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: