In Grails, how do I specify jars needed by an ivy

2019-02-28 08:27发布

问题:

In a grails project I have added a custom ivy resolver per the reference docs, http://www.grails.org/doc/latest/guide/single.html#12.2%20Plugin%20Repositories .

However, this resolver requires jsch and and some other jars. How can I put them on the project's build classpath so that ivy will use them?

This is my BuildConfig.groovy

grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"
grails.project.war.file = "target/${appName}-${appVersion}.war"

//Configure resolver
def sshResolver = new org.apache.ivy.plugins.resolver.SshResolver()
['libraries', 'builds'].each {
    sshResolver.addArtifactPattern("/home/ivy/[organisation]/[revision]/[artifact].[ext]")
    sshResolver.addIvyPattern("/home/ivy/[organisation]/[revision]/[artifact].[ext]")
}
sshResolver.name = "ssh"
sshResolver.settings = ivySettings

resolver sshResolver

grails.project.dependency.resolution = {
    // inherit Grails' default dependencies
    inherits("global") {
    }
    log "warn" 
    repositories {
        grailsPlugins()
        grailsHome()
        grailsCentral()
        ssh()
    }
    dependencies {
        compile 'someorg:somejar:1.0'
        runtime 'mysql:mysql-connector-java:5.1.13'
    }   
}

回答1:

I had the same problem and got this answer from the Ian Roberts on the Grails user list which works for me:

def myCL = new URLClassLoader([new File(
            "${basedir}/lib/the.jar"
        ).toURI().toURL()] as URL[],
        org.apache.ivy.plugins.repository.AbstractRepository.classLoader)
resolver myCL.loadClass('com.whatever.MyResolver').newInstance()

Passing the class loader that loaded Ivy as the parent is important so that it can resolve Ivy classes.

If you need to load multiple jars (because the class you are loading depends on them), then put all the files in the list like so:

def myCL = new URLClassLoader([
        "${basedir}/lib/jar1",
        "${basedir}/lib/jar2", // etc.
    ].collect { new File(it).toURI().toURL() } as URL[],
    org.apache.ivy.plugins.repository.AbstractRepository.classLoader)
resolver myCL.loadClass('com.whatever.MyResolver').newInstance()


回答2:

Another option that seems to work is to use @Grab. Something like:

@Grab(group="com.jcraft",module="jsch",version="0.1.42")
import org.apache.ivy.plugins.resolver.SshResolver

def sshResolver = new SshResolver()
['libraries', 'builds'].each {
    sshResolver.addArtifactPattern("/home/ivy/[organisation]/[revision]/[artifact].[ext]")
    sshResolver.addIvyPattern("/home/ivy/[organisation]/[revision]/[artifact].[ext]")
}
sshResolver.name = "ssh"
sshResolver.settings = ivySettings

resolver sshResolver

If your jar isn't in a public repository, it may be a little trickier.



回答3:

Grails uses ivy to implement it's dependency management. All you should need to do is declare the extra libraries you need. Have you tried something like this:

dependencies {
    ..
    compile 'com.jcraft:jsch:0.1.42'
    ..
}   


回答4:

Apparently

grails -cp ./lib/jsch.jar 

was the answer, not the -classpath or --classpath that I had initially tried.

If anyone has a better answer I will certainly accept it over mine.

I tried placing the jar in grails/lib but it gets loaded after the resolvers are processed.

I tried this in PreInit.groovy but no luck there either.

grails.compiler.dependencies = { fileset(file:'${basedir}/lib/jsch.jar') }