Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running Groovy script from Gradle using GroovyShell: Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/cli/ParseException

Tags:

gradle

groovy

I want to run a groovy command-line script from my Gradle build script.

I'm using this code in my Gradle script:

def groovyShell = new GroovyShell();
groovyShell.run(file('script.groovy'), ['arg1', 'arg2'] as String[])

Things work fine until my Groovy script (script.groovy) uses the CliBuilder class. Then I get the following exception:

org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.NoClassDefFoundError: org/apache/commons/cli/ParseException ... Caused by: java.lang.ClassNotFoundException: org.apache.commons.cli.ParseException

I found lots of people with similar problems and errors, but "the solution" was difficult to extract from the numerous posts I read. Lots of people suggested putting the commons-cli jar on the classpath, but doing so for the GroovyShell was not at all apparent to me. Also, I had already declared @Grapes and @Grab for my required libraries in the script.groovy, so it should have everything it needed.

like image 974
Taytay Avatar asked Dec 07 '12 12:12

Taytay


2 Answers

Thanks to this unaccepted SO answer, I finally found what I needed to do:

//define our own configuration
configurations{
    addToClassLoader
}
//List the dependencies that our shell scripts will require in their classLoader:
dependencies {
    addToClassLoader group: 'commons-cli', name: 'commons-cli', version: '1.2'
}
//Now add those dependencies to the root classLoader:
URLClassLoader loader = GroovyObject.class.classLoader
configurations.addToClassLoader.each {File file ->
    loader.addURL(file.toURL())
}

//And now no more exception when I run this:
def groovyShell = new GroovyShell();
groovyShell.run(file('script.groovy'), ['arg1', 'arg2'] as String[])

You can find more details about classLoaders and why this solution works in this forum post.

Happy scripting!

(Before you downvote me for answering my own question, read this)

like image 156
Taytay Avatar answered Sep 21 '22 09:09

Taytay


The alternative to do this is the following:

buildScript {
  repositories { mavenCentral() }
  dependencies {
    classpath "commons-cli:commons-cli:1.2"
  }
}

def groovyShell = new GroovyShell()
....

This puts the commons-cli dependency on the classpath of the buildscript instead of on the classpath of the project to be built.

like image 35
Hiery Nomus Avatar answered Sep 21 '22 09:09

Hiery Nomus