jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
Signup
groovy
  • groovy
  • GROOVY-3583

Grape issues

  • Log In
  • Views
    • XML
    • Word
    • Printable

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

is related to

Improvement - An improvement or enhancement to an existing feature or task. GROOVY-3730 Provide more control for @Grapes to exclude transitives or adjust classloader

  • Major - Major loss of function.
  • Closed - The issue is considered finished, the resolution is correct. Issues which are not closed can be reopened.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • Work Log
  • History
  • Activity
Hide
Permalink
Keith Hyland added a comment - 17/Jun/09 3:17 AM - 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 - 17/Jun/09 3:17 AM - 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)
Hide
Permalink
Keith Hyland added a comment - 18/Jun/09 6:34 AM - 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 - 18/Jun/09 6:34 AM - 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
Permalink
Matias Bjarland added a comment - 22/Jul/09 4:08 PM

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 - 22/Jul/09 4:08 PM 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
Permalink
Paul King added a comment - 23/Jul/09 6:34 PM

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 - 23/Jul/09 6:34 PM 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
Permalink
Ken Weiner added a comment - 27/Aug/09 6:10 PM

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 - 27/Aug/09 6:10 PM 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
Permalink
Roztworowska added a comment - 29/Aug/09 9:37 PM

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 - 29/Aug/09 9:37 PM 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
Permalink
Matthew Corby-Eaglen added a comment - 03/Sep/09 1:22 PM

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 - 03/Sep/09 1:22 PM 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
Permalink
Hubert Klein Ikkink added a comment - 04/Sep/09 6:34 AM

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 - 04/Sep/09 6:34 AM 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
Permalink
Matthew Corby-Eaglen added a comment - 04/Sep/09 7:18 AM

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 - 04/Sep/09 7:18 AM 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
Permalink
Hubert Klein Ikkink added a comment - 05/Sep/09 7:46 AM

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 - 05/Sep/09 7:46 AM 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
Permalink
Paul King added a comment - 07/Sep/09 4:57 PM

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 - 07/Sep/09 4:57 PM 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
Permalink
Paul King added a comment - 08/Sep/09 7:48 PM

Please see GROOVY-3730 for one potential solution.

Show
Paul King added a comment - 08/Sep/09 7:48 PM Please see GROOVY-3730 for one potential solution.
Hide
Permalink
John Hurst added a comment - 08/Sep/09 10:49 PM

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 - 08/Sep/09 10:49 PM 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
Permalink
Paul King added a comment - 11/Sep/09 3:50 AM

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 - 11/Sep/09 3:50 AM 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
Permalink
Hubert Klein Ikkink added a comment - 14/Sep/09 5:23 AM

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 - 14/Sep/09 5:23 AM I think @GrabConfig doesn't have to be back-ported to 1.6.5. We have workarounds to get around the issue.
Hide
Permalink
Paul King added a comment - 14/Sep/09 8:54 AM

So, everyone happy if we close this issue?

Show
Paul King added a comment - 14/Sep/09 8:54 AM So, everyone happy if we close this issue?
Hide
Permalink
Keith Hyland added a comment - 14/Sep/09 9:01 AM

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

Show
Keith Hyland added a comment - 14/Sep/09 9:01 AM Yes, Fine with me, the workarounds should suffice for 1.6
Hide
Permalink
Paul King added a comment - 14/Sep/09 9:24 AM

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

Show
Paul King added a comment - 14/Sep/09 9:24 AM Fixed in 1.7 thanks to GROOVY-3730 . Workarounds exist for Groovy 1.6.
Hide
Permalink
Matthias Hryniszak added a comment - 12/Mar/11 6:31 AM

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 - 12/Mar/11 6:31 AM 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
Permalink
Paul King added a comment - 12/Mar/11 9:33 PM

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 - 12/Mar/11 9:33 PM 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
Permalink
Haug Bürger added a comment - 15/Jun/11 8:32 AM

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 - 15/Jun/11 8:32 AM 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
Vote (5)
Watch (8)

Dates

  • Created:
    16/Jun/09 11:40 AM
    Updated:
    15/Jun/11 8:32 AM
    Resolved:
    14/Sep/09 9:24 AM
  • Atlassian JIRA (v5.2.7#850-sha1:b2af0c8)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.