Groovy with Grape and AntBuilder classloader probl

2020-06-04 03:25发布

问题:

I wanted to use groovy for a little ftp script and found this post http://www.hhhhq.org/blog/2009/05/01/ftp-using-groovy-and-ant/ Since there were several dependencies I wanted to use Grape. All dependencies are resolved and present in the cache. But I can't get Ant to find the optional tasks in the other libs. It always says

Caught: : Problem: failed to create task or type ftp
Cause: the class org.apache.tools.ant.taskdefs.optional.net.FTP was not found.
        This looks like one of Ant's optional components.
Action: Check that the appropriate optional JAR exists in
        -ANT_HOME\lib
        -the IDE Ant configuration dialogs

Do not panic, this is a common problem.
The commonest cause is a missing JAR.

This is not a bug; it is a configuration problem

        at GrabTest.runMe(GrabTest.groovy:15)
        at GrabTest.run(GrabTest.groovy:26)

Groovy Version: 1.6.5 JVM: 1.6.0_15

Here is my source code

@Grab(group='ant', module='ant', version='[1.6.5,)')
@Grab(group='ant', module='ant-nodeps', version='[1.0,)')
@Grab(group='ant', module='ant-apache-oro', version='[1.0,)') 
@Grab(group='ant', module='ant-commons-net', version='[1.0,)') 
@Grab(group='apache-oro', module='jakarta-oro', version='[2.0.8,)')
@Grab(group='commons-net', module='commons-net', version='[1.4,)')
def runMe() {
    // works
    println getClass().getClassLoader().loadClass("org.apache.tools.ant.taskdefs.optional.net.FTP")

    def ant = new AntBuilder()

    println getClass().getClassLoader() //groovy.lang.GroovyClassLoader$InnerLoader
    println ant.getClass().getClassLoader() //org.codehaus.groovy.tools.RootLoader
    ant.ftp( server:"ftp.foo.com",
            userid:"user",
            password:"passwd",
            passive:"yes",
            verbose:"yes",
            remotedir:"/pub/incoming",
            binary:"yes" ) {
                fileset( dir:"." ) { include( name:"**/*.gz" ) }
            }
}

runMe()

As you can see I suspect the classloader of being the problem, it seems that Grape doesn't inject the dependencies there. Any idea of how I can get it to work?

回答1:

You're right suspecting the classloader to be the root of the problem. As your code already reveals, the AntBuilder is loaded from the RootLoader, that doesn't have access to the classes loaded by the @Grab annotation. As GROOVY-3730 shows, Groovy 1.7 is going to address this problem.

However, you can solve your problem by directly using the groovy.grape.Grape.grab(Map dependency) method, in which you can set a specific classloader that should be used to load the dependencies:

import groovy.grape.Grape;

Grape.grab(group:'ant', module:'ant', version:'1.6.5', classLoader:this.class.classLoader.rootLoader)
Grape.grab(group:'ant', module:'ant-nodeps', version:'1.6.5', classLoader:this.class.classLoader.rootLoader)
Grape.grab(group:'ant', module:'ant-apache-oro', version:'1.6.5', classLoader:this.class.classLoader.rootLoader)
Grape.grab(group:'ant', module:'ant-commons-net', version:'1.6.5', classLoader:this.class.classLoader.rootLoader)
Grape.grab(group:'commons-net', module:'commons-net', version:'1.4.1', classLoader:this.class.classLoader.rootLoader)
Grape.grab(group:'oro', module:'oro', version:'2.0.8', classLoader:this.class.classLoader.rootLoader)


回答2:

Or just simply use

@GrabConfig(systemClassLoader=true)

Further info can be found: http://groovy.codehaus.org/Grape