phaseless wrote:
Hello Adam,
thank you very much. This really works!!!
However, I'm curious to understand why, but don't do it in detail.
Here is my code, that works:
configurations {
driver
}
repositories {
flatDir name: 'localRepository', dirs: 'lib'
}
dependencies {
driver name: 'ojdbc14'
}
task sql << {
URLClassLoader loader = GroovyObject.class.classLoader
configurations.driver.each {File file ->
loader.addURL(file.toURL())
}
Class driverClass = loader.loadClass('oracle.jdbc.OracleDriver')
// You might need one or both of these as well
Driver driverInstance = driverClass.newInstance()
java.sql.DriverManager.registerDriver(driverInstance)
Sql sql = Sql.newInstance("jdbc:oracle:thin:@server:1521:SID","usr","pswd")
}
There are two things, I'm interested in:
- I tried similar with
'URLClassLoader loader = this.class.classLoader'
instead of
'URLClassLoader loader = GroovyObject.class.classLoader'
but it did not work. I know about the different phases of gradle but why
does GroovyObject make the big
difference?
Groovy is loaded in a shared ClassLoader (along with the Gradle API, and
so on). Each project build script gets it's own ClassLoader with the
shared one as parent. So, GroovyObject.class.classLoader refers to the
ClassLoader which contains Groovy, and this.class.classLoader refers to
the build script ClassLoader.
When you call Sql.newInstance(), it calls
DriverManager.createConnection(), which will only allow access to the
drivers loaded by the same ClassLoader as the caller. Because Sql is
part of Groovy, it is in the Groovy ClassLoader. This means you must add
the driver classes to the Groovy ClassLoader so that they are visible to
Sql. If you use the build script ClassLoader, the driver classes won't
be visible.
- The second thing is: Why does it make a difference to have the
configuration 'driver', although this
is not used anywhere in the task? Does this mean that all files of all
defined configurations add
up to a big 'Classpath' supplied to the tasks of 'build.gradle'?
The alternative formulation
loader.addURL ( new File('lib/ojdbc.jar').toURL() )
instead of the configurations.driver.each-Closure does not work!!! Why
not?
Using a file should work - perhaps try
loader.addURL ( new File('lib/ojdbc.jar').*toURI().*toURL() )
Perhaps my knowledge of gradle i to limited yet.
I suspect its more due to DriverManager's awkward API.
May be the actual
documentation lacks in a general
introductory chapter about the meaning of configurations, dependencies,
artifacts ... for those
who do not come as a Maven or Ivy adept.
I think that's true.
Nevertheless I want to say that I admire the consice and straight forward
style of the documentation
and that I'm very happy about the agility and velocity of the develoment.
Thank you very much
Christoph
Adam Murdoch-2 wrote:
DriverManager will only let you access drivers which have been loaded by
the calling class' classloader. In the build script, the caller to
DriverManager isn't actually the build script, it is Groovy. So, you
need to load the driver in the same classloader as Groovy.
Here is an example. It uses H2, but should work with the Oracle driver
too.
configurations {
driver
}
dependencies {
driver "com.h2database:h2:1.2.120"
}
URLClassLoader loader = GroovyObject.class.classLoader
configurations.driver.each {File file ->
loader.addURL(file.toURL())
}
Class driver = loader.loadClass('org.h2.Driver')
// You might need one or both of these as well
// Driver instance = driver.newInstance()
// DriverManager.registerDriver(instance)
Sql sql = Sql.newInstance("jdbc:h2:$buildDir/test", "sa", "")
--
Adam Murdoch
Gradle Developer
http://www.gradle.org
--
Adam Murdoch
Gradle Developer
http://www.gradle.org