简体   繁体   中英

How do I set an embedded Groovy scripts classpath?

I am trying to extend an Eclipse code builder (for generating DTOs from Hibernate VOs) - and it uses Groovy for its template system.

The code it uses to create the groovy Script is a little weird (not what I see in the Groovy docs) but it works, mostly:

GroovyShell shell = new GroovyShell();
script = shell.parse(source);

Then, later:

Binding binding = (bindings == null ? new Binding() : new Binding(bindings));
Script scriptInstance = InvokerHelper.createScript(script.getClass(), binding);
scriptInstance.setProperty("out", out);
scriptInstance.run();
out.flush();

Now, this works just fine, until it hits a reference to an object that is not directly in the project. In the script, it iterates through the properties of the Class that it is processing - when it does this, Groovy looks at all of the methods and when it can't find a Class definition for one of the method parameters, it craps out. In this case, it's dying when it finds any references to Hibernate, but I'm sure it will crap out with a lot more. It doesn't need to do anything to them, but it can't live without knowing what they are apparently.

Script doesn't appear to have a classloader that I can supply any classpath info, so I tried providing it to the GroovyShell - no difference.

What's the proper way to fix this so that the Groovy interpreter can find my projects referenced Jars?

The same as @James can be done without using reflection, loading all jar files from a certain folder:

URLClassLoader classLoader = new URLClassLoader( getExtraJarUrls(), getClass().getClassLoader() );
GroovyShell shell = new GroovyShell( classLoader, binding, compilerConfiguration );


private URL[] getExtraJarUrls() throws MalformedURLException
{
    logger.debug( "Loading extra jars from {}", EXTRA_JARS_DIR.getAbsolutePath() );
    URL[] result;
    File[] files = EXTRA_JARS_DIR.listFiles( new JarFilenameFilter() );
    if (files != null)
    {
        List<URL> urls = new ArrayList<URL>( files.length );
        for (File file : files)
        {
            urls.add( file.toURI().toURL() );
        }
        result = urls.toArray( new URL[urls.size()] );
    }
    else
    {
        result = new URL[0];
    }
    logger.debug( "Adding URLs to classloader: {}", Arrays.toString( result ) );
    return result;
}

private static class JarFilenameFilter implements FilenameFilter
{
    public boolean accept( File dir, String name )
    {
        return name.endsWith( ".jar" );
    }
}

I had this exact problem and solved it by creating my own URLClassLoader, and using reflection to call a protected method to add a new path to the ClassPath

// Specify the path you want to add
URL url = new URL("file://path/to/classes/here");

// Create a new class loader as a child of the default system class loader
ClassLoader loader = new URLClassLoader(System.getClass().getClassLoader()); 

// Get the AddURL method and call it
Method method = URLClassLoader.class.getDeclaredMethod("addURL",new Class[]{URL.class});
method.setAccessible(true);
method.invoke(loader,new Object[]{ url });

GroovyShell shell = new GroovyShell( loader );

I'm having the same problem trying to automate Gant scripts running. The solution I found is:

  1. copy gant-starter.conf (or groovy-starter.conf if it's just groovy) from $GROOVY_HOME/conf to your own dir;

  2. add "load [directory]" or "load [jar]" there, as described in javadocs to org.codehaus.groovy.tools.LoaderConfiguration, found in Groovy source distribution;

  3. before starting groovy set groovy.starter.conf.override system property to the name of that file, like -Dgroovy.starter.conf.override=[filename]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM