Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.6.3
    • Fix Version/s: 1.7-beta-2
    • Component/s: Grape
    • Labels:
      None
    • Environment:
      jdk 1.5-06
      groovy 1.6.3
      WIndows xp
    • Number of attachments :
      0

      Description

      I have a simple piece of groovy for accessing a (oracle) DB.

      The code works fine once I include the jdbc jar in my $GROOVY_HOME/lib folder.

      However I would like to use grape to dynamically manage dependencies so I changed the code to below.

      import groovy.grape.Grape
      
      Grape.grab(group:'oracle', module:'ojdbc14', version:'10.1.0.4.0' )
      import groovy.sql.Sql
      import java.sql.Time
      
      def db = Sql.newInstance("jdbc:oracle:thin:@flagtest.intmet.ie:1525:BEAM", "user", "password", 
      		"oracle.jdbc.driver.OracleDriver")
      

      This results in

      Caught: java.sql.SQLException: No suitable driver
              at t2.run(t2.groovy:8)
      

      If I add the following import after the Grape.grab

      import oracle.jdbc.driver.OracleDriver
      

      I get the following

      org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
      C:\dev\t2.groovy: 4: unable to resolve class oracle.jdbc.driver.OracleDriver
       @ line 4, column 1.
         import oracle.jdbc.driver.OracleDriver;
         ^
      

        Issue Links

          Activity

          Hide
          Keith Hyland added a comment - - edited

          I've also noticed different behaviour using the @Grab annotation.

          The following code

          import groovy.sql.Sql
          import java.sql.Time
          
          @Grab(group='oracle', module='ojdbc14', version='10.1.0.4.0' )
          
          def db = Sql.newInstance("jdbc:oracle:thin:@dbUrl:1525:BEAM", "xxx", "xxxx",
          "oracle.jdbc.driver.OracleDriver")
          

          returns Caught: java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
          at t2.run(t2.groovy:6)

          Show
          Keith Hyland added a comment - - edited I've also noticed different behaviour using the @Grab annotation. The following code import groovy.sql.Sql import java.sql.Time @Grab(group='oracle', module='ojdbc14', version='10.1.0.4.0' ) def db = Sql.newInstance( "jdbc:oracle:thin:@dbUrl:1525:BEAM" , "xxx" , "xxxx" , "oracle.jdbc.driver.OracleDriver" ) returns Caught: java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver at t2.run(t2.groovy:6)
          Guillaume Laforge made changes -
          Field Original Value New Value
          Description I have a simple piece of groovy for accessing a (oracle) DB.

          The code works fine once I include the jdbc jar in my $GROOVY_HOME/lib folder.

          However I would like to use grape to dynamically manage dependencies so I changed the code to below.

          import groovy.grape.Grape

          Grape.grab(group:'oracle', module:'ojdbc14', version:'10.1.0.4.0' )
          import groovy.sql.Sql
          import java.sql.Time

          def db = Sql.newInstance("jdbc:oracle:thin:@flagtest.intmet.ie:1525:BEAM", "rjensen", "deltaforce",
          "oracle.jdbc.driver.OracleDriver")


          This results in
          Caught: java.sql.SQLException: No suitable driver
                  at t2.run(t2.groovy:8)

          If I add the following import after the Grape.grab
          import oracle.jdbc.driver.OracleDriver
          I get the following
          org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
          C:\dev\t2.groovy: 4: unable to resolve class oracle.jdbc.driver.OracleDriver
           @ line 4, column 1.
             import oracle.jdbc.driver.OracleDriver;
             ^
          I have a simple piece of groovy for accessing a (oracle) DB.

          The code works fine once I include the jdbc jar in my $GROOVY_HOME/lib folder.

          However I would like to use grape to dynamically manage dependencies so I changed the code to below.
          {code}
          import groovy.grape.Grape

          Grape.grab(group:'oracle', module:'ojdbc14', version:'10.1.0.4.0' )
          import groovy.sql.Sql
          import java.sql.Time

          def db = Sql.newInstance("jdbc:oracle:thin:@flagtest.intmet.ie:1525:BEAM", "user", "password",
          "oracle.jdbc.driver.OracleDriver")
          {code}

          This results in
          {code}
          Caught: java.sql.SQLException: No suitable driver
                  at t2.run(t2.groovy:8)
          {code}
          If I add the following import after the Grape.grab
          {code}
          import oracle.jdbc.driver.OracleDriver
          {code}
          I get the following
          {code}
          org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
          C:\dev\t2.groovy: 4: unable to resolve class oracle.jdbc.driver.OracleDriver
           @ line 4, column 1.
             import oracle.jdbc.driver.OracleDriver;
             ^
          {code}
          Hide
          Keith Hyland added a comment - - edited

          There seems also to be different behaviour depending on whether the groovy script contain a class or not.
          The following code (semantically identical to above), results in a different error.

           
          import groovy.sql.Sql
          import java.sql.Time
          
          @Grab(group='oracle', module='ojdbc14', version='10.1.0.4.0' )
          public class t2{
          	public static void main(String[] args){
          		def db = Sql.newInstance("jdbc:oracle:thin:@flagtest.intmet.ie:1525:BEAM", "user", "password",
          		"oracle.jdbc.driver.OracleDriver")
          	}
          }
          

          Caught: java.sql.SQLException: No suitable driver
          at t2.main(t2.groovy:7)

          Show
          Keith Hyland added a comment - - edited There seems also to be different behaviour depending on whether the groovy script contain a class or not. The following code (semantically identical to above), results in a different error. import groovy.sql.Sql import java.sql.Time @Grab(group='oracle', module='ojdbc14', version='10.1.0.4.0' ) public class t2{ public static void main(String[] args){ def db = Sql.newInstance("jdbc:oracle:thin:@flagtest.intmet.ie:1525:BEAM", "user", "password", "oracle.jdbc.driver.OracleDriver") } } Caught: java.sql.SQLException: No suitable driver at t2.main(t2.groovy:7)
          Hide
          Matias Bjarland added a comment -

          I ran into this with mysql drivers. Although it totally defeats the purpose of grape, I can get my code working by adding the jar to my classloader using something like:

           
          public void addFileToClassPath(String fileName) {
              addFileToClassPath(new File(fileName))
          }
          
          public void addFileToClassPath(File file) {
              println("Classpath <-- ${file.path}");
          
              def loader = this.class.classLoader
              (loader.rootLoader ?: loader.systemClassLoader).addURL(file.toURL())
          }
          


          and sending in a valid driver file. So maybe grape should be doing this in some fashion and it isn't? Hopefully this can provide a hint to some kind soul so they can fix this...or help somebody get their script running.

          Show
          Matias Bjarland added a comment - I ran into this with mysql drivers. Although it totally defeats the purpose of grape, I can get my code working by adding the jar to my classloader using something like: public void addFileToClassPath( String fileName) { addFileToClassPath( new File(fileName)) } public void addFileToClassPath(File file) { println( "Classpath <-- ${file.path}" ); def loader = this .class.classLoader (loader.rootLoader ?: loader.systemClassLoader).addURL(file.toURL()) } and sending in a valid driver file. So maybe grape should be doing this in some fashion and it isn't? Hopefully this can provide a hint to some kind soul so they can fix this...or help somebody get their script running.
          Hide
          Paul King added a comment -

          Not really an update but just a note that we don't currently expect Keith's first comment to currently work, i.e. this one:
          http://jira.codehaus.org/browse/GROOVY-3583?focusedCommentId=180620&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_180620

          Grab annotations must currently annotate a class or method.
          In the next release this will also include imports and package definitions.
          Some time in the future, also variable expressions like Keith's first comment.

          The second thing you are noticing is possibly related to different classloaders coming into play. I'll need to play a bit more to confirm.

          Show
          Paul King added a comment - Not really an update but just a note that we don't currently expect Keith's first comment to currently work, i.e. this one: http://jira.codehaus.org/browse/GROOVY-3583?focusedCommentId=180620&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_180620 Grab annotations must currently annotate a class or method. In the next release this will also include imports and package definitions. Some time in the future, also variable expressions like Keith's first comment. The second thing you are noticing is possibly related to different classloaders coming into play. I'll need to play a bit more to confirm.
          Hide
          Ken Weiner added a comment -

          We are experiencing this problem as well with the MySQL driver:

          Caught: java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/testdb
          

          Things work when the driver is in .groovy/lib, but not when missing from .groovy/lib and referenced solely from @Grab as shown below:

          @Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
          
          Show
          Ken Weiner added a comment - We are experiencing this problem as well with the MySQL driver: Caught: java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/testdb Things work when the driver is in .groovy/lib, but not when missing from .groovy/lib and referenced solely from @Grab as shown below: @Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
          Hide
          Roztworowska added a comment -

          dirty workaround,
          based on idea http://jira.codehaus.org/browse/GROOVY-3583?focusedCommentId=184570&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_184570
          just works...

          import groovy.sql.Sql;
          
          @Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
           
          def loadDriverJar(toLoad)
          {	
          	//extract path to .jar file
          	def res='/'+toLoad.replaceAll('\\.','/')+'.class';	
          	def c=this.class.classLoader.loadClass(toLoad);
          	def file=''+ c.getResource(res).file;	
          	file=file.substring(0,file.size()-(res.size()+1));
          
          	// add .jar to systemClassLoader 
          	ClassLoader.systemClassLoader.addURL(new URL(file));	
          }
          
          def createSql()
          {
          	def driverClass="com.mysql.jdbc.Driver";
          	loadDriverJar(driverClass);	
          	def sql=Sql.newInstance("jdbc:mysql://localhost/test","root","",driverClass);
          	return sql;
          }
          
          def sql=createSql();
          println sql.firstRow("SELECT now( )");
          
          Show
          Roztworowska added a comment - dirty workaround, based on idea http://jira.codehaus.org/browse/GROOVY-3583?focusedCommentId=184570&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_184570 just works... import groovy.sql.Sql; @Grab(group='mysql', module='mysql-connector-java', version='5.1.6') def loadDriverJar(toLoad) { //extract path to .jar file def res='/'+toLoad.replaceAll('\\.','/')+'.class'; def c= this .class.classLoader.loadClass(toLoad); def file=''+ c.getResource(res).file; file=file.substring(0,file.size()-(res.size()+1)); // add .jar to systemClassLoader ClassLoader .systemClassLoader.addURL( new URL(file)); } def createSql() { def driverClass= "com.mysql.jdbc.Driver" ; loadDriverJar(driverClass); def sql=Sql.newInstance( "jdbc:mysql: //localhost/test" , "root" ,"",driverClass); return sql; } def sql=createSql(); println sql.firstRow( "SELECT now( )" );
          Hide
          Matthew Corby-Eaglen added a comment -

          A better solution is this:
          {{{
          import groovy.sql.Sql;
          import groovy.grape.Grape;

          Grape.grab(group:'mysql', module:'mysql-connector-java', version:'5.1.6' )

          this.class.classLoader.getURLs().each

          { ClassLoader.systemClassLoader.addURL(it); }

          def sql=Sql.newInstance("jdbc:mysql://localhost/test","root","", "com.mysql.jdbc.Driver");

          println sql.firstRow("SELECT now( )");

          }}}

          This way all dependencies of the driver are also referenced.

          Show
          Matthew Corby-Eaglen added a comment - A better solution is this: {{{ import groovy.sql.Sql; import groovy.grape.Grape; Grape.grab(group:'mysql', module:'mysql-connector-java', version:'5.1.6' ) this.class.classLoader.getURLs().each { ClassLoader.systemClassLoader.addURL(it); } def sql=Sql.newInstance("jdbc:mysql://localhost/test","root","", "com.mysql.jdbc.Driver"); println sql.firstRow("SELECT now( )"); }}} This way all dependencies of the driver are also referenced.
          Hide
          Hubert Klein Ikkink added a comment -

          Another solution:

          you can also use the classLoader property for Grape:

          Grape.grab(group:'mysql', module:'mysql-connector-java', version:'5.1.6', classLoader: this.class.classLoader.rootLoader)

          This will add the JAR to the Groovy Rootloader and Sql.newInstance can find the driver class.

          Show
          Hubert Klein Ikkink added a comment - Another solution: you can also use the classLoader property for Grape: Grape.grab(group:'mysql', module:'mysql-connector-java', version:'5.1.6', classLoader: this.class.classLoader.rootLoader) This will add the JAR to the Groovy Rootloader and Sql.newInstance can find the driver class.
          Hide
          Matthew Corby-Eaglen added a comment -

          however the map version does not seem work (extrapolating from mrhaki's example):

          Grape.grab([group:'com.thoughtworks.xstream', module:'xstream', version:"1.3.1", classLoader:ClassLoader.systemClassLoader],
          [group:'xpp3', module:'xpp3', version:'1.1.2a',classLoader:ClassLoader.systemClassLoader])
          

          but perhaps I have the wrong syntax?

          Show
          Matthew Corby-Eaglen added a comment - however the map version does not seem work (extrapolating from mrhaki's example): Grape.grab([group:'com.thoughtworks.xstream', module:'xstream', version: "1.3.1" , classLoader: ClassLoader .systemClassLoader], [group:'xpp3', module:'xpp3', version:'1.1.2a',classLoader: ClassLoader .systemClassLoader]) but perhaps I have the wrong syntax?
          Hide
          Hubert Klein Ikkink added a comment -

          The map version can be used like this:

          Grape.grab(
            /* arguments Map */
            [classLoader: ClassLoader.systemClassLoader], 
            /* dependencies Map*/
            [group:'com.thoughtworks.xstream', module:'xstream', version:"1.3.1"],  
            [group:'xpp3', module:'xpp3', version:'1.1.2a'] 
          )
          
          Show
          Hubert Klein Ikkink added a comment - The map version can be used like this: Grape.grab( /* arguments Map */ [classLoader: ClassLoader .systemClassLoader], /* dependencies Map*/ [group:'com.thoughtworks.xstream', module:'xstream', version: "1.3.1" ], [group:'xpp3', module:'xpp3', version:'1.1.2a'] )
          Hide
          Paul King added a comment -

          I have an experimental @GrabConfig(systemClassLoader=true) which can be added within a @Grape annotation to achieve the above. I'll post more details and ask for feedback shortly.

          Show
          Paul King added a comment - I have an experimental @GrabConfig(systemClassLoader=true) which can be added within a @Grape annotation to achieve the above. I'll post more details and ask for feedback shortly.
          Hide
          Paul King added a comment -

          Please see GROOVY-3730 for one potential solution.

          Show
          Paul King added a comment - Please see GROOVY-3730 for one potential solution.
          Paul King made changes -
          Link This issue is related to GROOVY-3730 [ GROOVY-3730 ]
          Hide
          John Hurst added a comment -

          Note that with Groovy 1.6, a perfectly reasonable solution is to switch from using the newInstance()/DriverManager way of creating a groovy.sql.Sql instance, and instead use the constructor taking a DataSource.

          For example, for Oracle:

          import oracle.jdbc.pool.OracleDataSource
          
          @Grab(group='com.oracle', module='ojdbc14', version='10.2.0.3.0') // assuming you have this in your grape repo
          void foo() {}
          
          url = "..."
          
          def db = new Sql(new OracleDataSource(URL: url))
          

          This works well for me. You do have to learn what the appropriate DataSource class is for your driver, and what it's properties are.

          John Hurst

          Show
          John Hurst added a comment - Note that with Groovy 1.6, a perfectly reasonable solution is to switch from using the newInstance()/DriverManager way of creating a groovy.sql.Sql instance, and instead use the constructor taking a DataSource. For example, for Oracle: import oracle.jdbc.pool.OracleDataSource @Grab(group='com.oracle', module='ojdbc14', version='10.2.0.3.0') // assuming you have this in your grape repo void foo() {} url = "..." def db = new Sql( new OracleDataSource(URL: url)) This works well for me. You do have to learn what the appropriate DataSource class is for your driver, and what it's properties are. John Hurst
          Hide
          Paul King added a comment -

          The current thinking is that @GrabConfig won't be back-ported to 1.6.5. Is having the solution for 1.7 good enough given that we have the Grape.grab() with classloaders workaround?

          Show
          Paul King added a comment - The current thinking is that @GrabConfig won't be back-ported to 1.6.5. Is having the solution for 1.7 good enough given that we have the Grape.grab() with classloaders workaround?
          Hide
          Hubert Klein Ikkink added a comment -

          I think @GrabConfig doesn't have to be back-ported to 1.6.5. We have workarounds to get around the issue.

          Show
          Hubert Klein Ikkink added a comment - I think @GrabConfig doesn't have to be back-ported to 1.6.5. We have workarounds to get around the issue.
          Hide
          Paul King added a comment -

          So, everyone happy if we close this issue?

          Show
          Paul King added a comment - So, everyone happy if we close this issue?
          Hide
          Keith Hyland added a comment -

          Yes, Fine with me, the workarounds should suffice for 1.6

          Show
          Keith Hyland added a comment - Yes, Fine with me, the workarounds should suffice for 1.6
          Hide
          Paul King added a comment -

          Fixed in 1.7 thanks to GROOVY-3730. Workarounds exist for Groovy 1.6.

          Show
          Paul King added a comment - Fixed in 1.7 thanks to GROOVY-3730 . Workarounds exist for Groovy 1.6.
          Paul King made changes -
          Status Open [ 1 ] Resolved [ 5 ]
          Resolution Fixed [ 1 ]
          Assignee Paul King [ paulk_asert ]
          Paul King made changes -
          Fix Version/s 1.7-beta-2 [ 15540 ]
          Paul King made changes -
          Status Resolved [ 5 ] Closed [ 6 ]
          Hide
          Matthias Hryniszak added a comment -

          Guys, I'm using Groovy Version: 1.8.0-rc-1 JVM: 1.6.0_23 and the problem with loading JDBC drivers still persists. Should I reopen this issue?

          Here's the example:

          @Grab('mysql:mysql-connector-java:5.1.15')
          import groovy.sql.Sql

          def sql = Sql.newInstance("jdbc:mysql://localhost:3306/example", "root", "", "com.mysql.jdbc.Driver")

          It produces the following exception:

          Caught: java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/example
          at test.run(test.groovy:4)

          Which is identical to the problem reported in this issue.

          The solution

          this.class.classLoader.getURLs().each{ 
            ClassLoader.systemClassLoader.addURL(it); 
          }
          

          still works.

          Show
          Matthias Hryniszak added a comment - Guys, I'm using Groovy Version: 1.8.0-rc-1 JVM: 1.6.0_23 and the problem with loading JDBC drivers still persists. Should I reopen this issue? Here's the example: @Grab('mysql:mysql-connector-java:5.1.15') import groovy.sql.Sql def sql = Sql.newInstance("jdbc:mysql://localhost:3306/example", "root", "", "com.mysql.jdbc.Driver") It produces the following exception: Caught: java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/example at test.run(test.groovy:4) Which is identical to the problem reported in this issue. The solution this.class.classLoader.getURLs().each{ ClassLoader.systemClassLoader.addURL(it); } still works.
          Hide
          Paul King added a comment -

          This seemed to work for me:

          @Grab('mysql:mysql-connector-java:5.1.15')
          @GrabConfig(systemClassLoader=true)
          ...
          

          So I don't think reopening is necessary.

          Show
          Paul King added a comment - This seemed to work for me: @Grab('mysql:mysql-connector-java:5.1.15') @GrabConfig(systemClassLoader= true ) ... So I don't think reopening is necessary.
          Hide
          Haug Bürger added a comment -

          I have a script that requires a JDBC driver and has a Xerces dependency. With the root classloader the JDBC driver loads, without the xerces dependency could be loaded. I want to reopen this issue.

          One solution could be to add the systemClassLoader property to the @Grab line to decide which classloader to use for this line and all dependencies of this line.

          Caught: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.apache.xerces.jaxp.SAXParserImpl.getParser()Lorg/xml/sax/Parser;" the class loader (instance of org/codehaus/groovy/tools/RootLoader) of the current class, org/apache/xerces/jaxp/SAXParserImpl, and its superclass loader (instance of <
          bootloader>), have different Class objects for the type org/xml/sax/Parser used in the signature
          at gutil.TestEnvironment.read(TestEnvironment.groovy:60)
          at gutil.TestEnvironment.<init>(TestEnvironment.groovy:22)
          at TcpIpTest1.run(TcpIpTest1.groovy:20)

          Show
          Haug Bürger added a comment - I have a script that requires a JDBC driver and has a Xerces dependency. With the root classloader the JDBC driver loads, without the xerces dependency could be loaded. I want to reopen this issue. One solution could be to add the systemClassLoader property to the @Grab line to decide which classloader to use for this line and all dependencies of this line. Caught: java.lang.LinkageError: loader constraint violation: when resolving overridden method "org.apache.xerces.jaxp.SAXParserImpl.getParser()Lorg/xml/sax/Parser;" the class loader (instance of org/codehaus/groovy/tools/RootLoader) of the current class, org/apache/xerces/jaxp/SAXParserImpl, and its superclass loader (instance of < bootloader>), have different Class objects for the type org/xml/sax/Parser used in the signature at gutil.TestEnvironment.read(TestEnvironment.groovy:60) at gutil.TestEnvironment.<init>(TestEnvironment.groovy:22) at TcpIpTest1.run(TcpIpTest1.groovy:20)

            People

            • Assignee:
              Paul King
              Reporter:
              Keith Hyland
            • Votes:
              5 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: