Why this tasks fails on ClassNotFoundException?


(Pavel Bernshtam) #1

Why this tasks fails on ClassNotFoundException ???

buildscript {
      repositories {
          mavenCentral()
      }
        dependencies {
          classpath 'postgresql:postgresql:9.0-801.jdbc4'
      }
  }
      task sql << {
      def driverName = 'org.postgresql.Driver'
      Class.forName(driverName)
      groovy.sql.Sql sql = Sql.newInstance('jdbc:postgresql://localhost:5432/aaa',
 'postgres',
   'a',
   driverName
)
      sql.execute 'create table test (id int not null)'
      sql.execute 'insert into test (id) values(1)'
      sql.eachRow 'select * from test' {
          println it
      }
  }

(René Groeschke) #2

Hello Pavel, you’re running into a classloader problem. The postgres driver class must be accessible from the classloader of the class who tries to instantiate the driver. In your example this is the groovy classloader and not the buildscript classloader. As a workaround, you can add custom libraries to the groovy classloader of your build script by:

configurations{
 driver
}
repositories {
    mavenCentral()
}
  dependencies {
    driver 'postgresql:postgresql:9.0-801.jdbc4'
}
  task sql << {
   URLClassLoader loader = GroovyObject.class.classLoader
   configurations.driver.each {File file ->
       loader.addURL(file.toURL())
   }
    def driverName = 'org.postgresql.Driver'
    groovy.sql.Sql sql = groovy.sql.Sql.newInstance('jdbc:postgresql://localhost:5432/aaa', 'postgres', 'a', driverName)
    sql.execute 'create table test (id int not null)'
    sql.execute 'insert into test (id) values(1)'
    sql.eachRow 'select * from test' {
        println it
    }
}

(Pavel Bernshtam) #3

Thank you, Rene, Can you point me to some diagram of gradle classloaders?


(René Groeschke) #4

Hey Pavel, sorry, I have no diagram of the gradle classloaders in place. I just sketched this simplified overview at http://yuml.me/63b9e545

hope that helps


(Vasilii Pupkin) #5

complex classloading techniques?


(Peter Niederwieser) #6

Gradle’s class loader hierarchy is (largely) irrelevant to the problem at hand. The important point is that Groovy’s ‘Sql’ class is only able to use JDBC drivers whose class can be loaded with the defining class loader of the Groovy runtime. This is due to ‘java.sql.DriverManager’'s use of ‘getCallerClassLoader()’, which works as intended for Java, but not for alternative languages like Groovy.