问题
I'm trying to evaluate Groovy script inside a Java app by using GroovyShell.
Problem: My program compiles ok, but gives me a NoClassDefFoundError at run-time.
TestClass.java:
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
class TestClass {
static Binding binding;
static GroovyShell shell;
public static void main(String[] args) {
System.out.println("Hello, world.");
binding = new Binding();
shell = new GroovyShell(binding);
Object value = shell.evaluate("5 ** 5");
}
}
Then I compile with:
> javac -cp %GROOVY_HOME%\embeddable\groovy-all-2.1.1.jar TestClass.Java
> jar cfm TestClass.jar Manifest.txt TestClass.class
It compiles without error. Then I run it:
> java -jar TestClass.jar
Hello, world
Exception in thread "main" java.lang.NoClassDefFoundError: groovy/lang/Binding
at TestClass.main(TestClass.java:10)
Caused by: java.lang.ClassNotFoundException: groovy.lang.Binding
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
Full error text: http://puu.sh/2gOrx
I've also tried running it with the same -cp as I compiled it, but it gives me the same error.
回答1:
Global classpath, for example, CLASSPATH environment and "-cp" option, won't take affect if you are running an executable JAR. Please refer to this post for details: Does java -jar option alter classpath options.
java - the Java application launcher document
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.
Instead, you need to set Class-Path in manifest file. Check the following sample.
File structure
|-- Manifest.txt
|-- TestClass.class
|-- TestClass.jar
|-- TestClass.java
`-- lib
`-- groovy-all-2.1.1.jar
Manifest.txt (don't forget to add a new line ending for last line)
Main-Class: TestClass
Class-Path: lib/groovy-all-2.1.1.jar
And execute the same commands in your question to generate and run an executable JAR. For more information, check this wiki page: Setting the path in a Manifest file.
回答2:
Instead of running the JAR directly, load the JAR into the classpath
and specify the class to run:
$ java -classpath $groovyJar:TestClass.jar TestClass
It's a little hacky because the Main-Class
is specified in the manifest but then taken from the command line. On the plus side, you don't have to hard-code the Class-Path
into the manifest.
The path to the Groovy JAR has changed since this question was asked a very long time ago. Assuming groovy
is in your PATH, one way to locate the Groovy JAR is:
$ groovyHome=$(dirname $(dirname $(which groovy)))
$ groovyJar=$groovyHome/lib/$(basename $groovyHome).jar
And the result will be something like:
$ which groovy
/Users/dem/apps/groovy/groovy-2.5.2/bin/groovy
$ echo $groovyJar
/Users/dem/apps/groovy/groovy-2.5.2/lib/groovy-2.5.2.jar
To build a JAR you can test with locally, create the Groovy file:
com/example/HelloWorld.groovy
package com.example
class HelloWorld {
static void main(String[] args) {
println "Hello, world."
}
}
Then issue the commands:
$ groovyc com/example/*.groovy
$ jar cfv HelloWorld.jar com/example/*.class
added manifest
adding: com/example/HelloWorld.class(in = 2829) (out= 1220)(deflated 56%)
$ ls -o
total 8
-rw-r--r-- 1 dem 1708 Oct 5 01:15 HelloWorld.jar
drwxr-xr-x 3 dem 96 Oct 5 01:10 com
$ java -classpath $groovyJar:HelloWorld.jar com.example.HelloWorld
Hello, world.
Note: The Groovy JAR (groovy-2.5.2.jar
) is 5.4MB, and the latest version (groovy-3.0.0-alpha-3.jar
) is 7.5MB.
来源:https://stackoverflow.com/questions/15399522/noclassdeffounderror-groovy-lang-binding