Why does DriverManager.getConnection() lookup fail in GroovyConsole?

1.9k views Asked by At

The following Groovy script works correctly from the command line. (I successfully get a Connection.)

// ---- jdbc_test.groovy
import java.sql.*
Class.forName("com.mysql.jdbc.Driver")
def con = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/test",
    "root",
    "password")
println con

> groovy -cp lib\mysql-connector-java-5.1.25-bin.jar script\jdbc_test.groovy
com.mysql.jdbc.JDBC4Connection@6025e1b6

But if the same script is loaded into GroovyConsole (2.4.3) and run - after adding the mysql-connector-java-5.1.25-bin.jar using 'Script' | 'Add Jar(s) to ClassPath' - it fails:

java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/test
at java_sql_DriverManager$getConnection.call(Unknown Source)
at jdbc_test.run(jdbc_test.groovy:3)

Every other package or class I have added to the classpath in GroovyConsole and experimented with has worked. Is there some unexpected interaction of Groovy's class loading and the way DriverManager works?

Is there a way around this? I'm trying to use the GroovyConsole to interactively test out some JDBC code (a library of functions, each of which takes a Connection as its first argument).

UPDATE: The Class.forName() part appears to be working fine. If I 'Script' | 'Clear Script Context' and rerun the script in GroovyConsole, I instead get:

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

If I add mysql-connector-java-5.1.25-bin.jar back in, I go back to getting:

java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/test
1

There are 1 answers

2
blackdrag On BEST ANSWER

Solution: The driver has to be on the classpath.

Reason: If you look into the DriverManager class you find code like this: Class.forName(driver.getClass().getName(), true, classLoader);. This is to check if the driver is accessible from your classloader context. And that context is determined by going back to the class that is calling he DriverManager. This code is written for Java, thus assumes a certain amount of frames on the call stack to go back. Since Groovy does not do direct calls (unless you use @CompileStatic) this number is wrong and leads usually to a Groovy core class to be selected, resulting in Groovy main loader to be selected.... in the past this was often even the JDK system classloader because of reflection. So even though the driver is loaded and registered, it is not accessible to you.

Note: with jdbc4 the driver should register itself, just by being on the classpath