Commons Dbcp
  1. Commons Dbcp
  2. DBCP-333

Unable to create a JDBC driver using custom class loader

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.3, 1.4
    • Fix Version/s: 1.3.1, 1.4.1
    • Labels:
      None

      Description

      Hello,

      I'm unable to instantiate my JDBC driver using a custom class loader:
      BasicDataSource ds = new BasicDataSource();
      String connectURL = "jdbc:mysql://"config.getHost()"/"+config.getDatabaseName();
      ds.setDriverClassName(MySQLStore.MYSQL_DRIVER);
      ds.setDriverClassLoader(config.getClass().getClassLoader());
      .....

      Having a look at the org.apache.commons.dbcp.BasicDataSource.createConnectionFactory() method implementation, I found that the class loader is actually ignored. In the first part of the method there is an attempt to load the class that seems to pass successfully, but the loaded class is not assigned to the driverFromCCL variable:
      if (driverClassLoader == null)

      { Class.forName(driverClassName); }

      else

      { Class.forName(driverClassName, true, driverClassLoader); }

      Then in the second part of the method driverFromCCL is still null and instead of instantiating the driver directly, DriverManager.getDriver(url) is called, which fails:
      if (driverFromCCL == null)

      { driver = DriverManager.getDriver(url); }

      else {
      // Usage of DriverManager is not possible, as it does not
      // respect the ContextClassLoader
      driver = (Driver) driverFromCCL.newInstance();
      if (!driver.acceptsURL(url))

      { throw new SQLException("No suitable driver", "08001"); }

      }

      Kind regards,
      Krasimir

        Issue Links

          Activity

          Hide
          Dennie de Lange added a comment -

          Hello, I have the same problem. Please update BasicDataSource.java.

          Change line 1417:
          Class.forName(driverClassName, true, driverClassLoader);
          To:
          driverFromCCL = driverClassLoader.loadClass(driverClassName);

          Show
          Dennie de Lange added a comment - Hello, I have the same problem. Please update BasicDataSource.java. Change line 1417: Class.forName(driverClassName, true, driverClassLoader); To: driverFromCCL = driverClassLoader.loadClass(driverClassName);
          Hide
          Joerg Schaible added a comment -

          @Dennie: Sun explicitly stated that Class.forName is recommended (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500212) and I cannot see what it changes regarding the reported bug.

          Show
          Joerg Schaible added a comment - @Dennie: Sun explicitly stated that Class.forName is recommended ( http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6500212 ) and I cannot see what it changes regarding the reported bug.
          Hide
          Mark Smit added a comment -

          We ran into the same issue. I can confirm that Dennie de Lange's suggested code modification in line 1417 works fine.

          Show
          Mark Smit added a comment - We ran into the same issue. I can confirm that Dennie de Lange's suggested code modification in line 1417 works fine.
          Hide
          Phil Steitz added a comment -

          Thanks for the report and comments. Patch looks good to me.

          Show
          Phil Steitz added a comment - Thanks for the report and comments. Patch looks good to me.
          Hide
          Sebb added a comment -

          What about the line a bit earlier which is called if driverClassLoader == null:

          Class.forName(driverClassName);

          In that case, driverFromCCL won't be initialised either.

          It's not clear to me what the code is trying to achieve, but at least at present it is self-consistent.
          Replacing only one of the Class.forName() calls does not seem correct to me.

          ==

          Also, why not replace:

          Class.forName(driverClassName, true, driverClassLoader);

          with

          driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);

          Would that not work just as well? Similarly for

          Class.forName(driverClassName);

          ==

          The method could do with some Javadoc TLC to explain when the URL is used, and when the classname is used.

          Show
          Sebb added a comment - What about the line a bit earlier which is called if driverClassLoader == null: Class.forName(driverClassName); In that case, driverFromCCL won't be initialised either. It's not clear to me what the code is trying to achieve, but at least at present it is self-consistent. Replacing only one of the Class.forName() calls does not seem correct to me. == Also, why not replace: Class.forName(driverClassName, true, driverClassLoader); with driverFromCCL = Class.forName(driverClassName, true, driverClassLoader); Would that not work just as well? Similarly for Class.forName(driverClassName); == The method could do with some Javadoc TLC to explain when the URL is used, and when the classname is used.

            People

            • Assignee:
              Mark Thomas
              Reporter:
              Krasimir Nedkov
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development