Taytay
Taytay

Reputation: 11352

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

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.

Upvotes: 6

Views: 6690

Answers (2)

Hiery Nomus
Hiery Nomus

Reputation: 17769

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.

Upvotes: 2

Taytay
Taytay

Reputation: 11352

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)

Upvotes: 8

Related Questions