Using groovyc To Compile Groovy Scripts

For most Groovy scripts I use, I simply run the script from its Groovy source code as-is and allow the compilation to take place implicitly.  However, it can be helpful at times to use groovyc to compile Groovy code into .class files and then execute those .class files via the normal Java launcher (java).  The groovyc compiler is also a necessity when mixing Groovy and Java code in the same compilation step.

For traditional Java, such as the HelloWorld.java class shown next, javac is used to compile the class into a .class file and then java is used to run that class file.  The example class is shown first followed by a screen snapshot showing the compilation and execution process.

HelloWorld.java

import static java.lang.System.out;
import java.util.Date;

public class HelloWorld
{
public static void main(String[] args)
{
out.println("Hello, " + args[0] + ", the time is " + new Date());
}
}

When running Groovy scripts, I usually run the script directly.  A simple Groovy script equivalent of the above Java class is shown next and is followed by a screen snapshot demonstrating running the script directly.  There is no .class file in the directory.

helloToWorld.groovy

println "Hello, ${args[0]}, the time is ${new Date()}"

The above approach to running Groovy scripts is the approach I typically take.  However, there are times when it is advantageous to explicitly compile a Groovy script into a .class file using groovyc and then run it just as one would run a file created with javac.  This is demonstrated in the next screen snapshot for the simple helloToWorld.groovy script shown above.

To run the Groovy script with the normal java launcher, it was necessary to include the Groovy JAR file on the classpath (I took advantage of Java 6’s JAR wildcard specification feature in this case to include all JARs in the Groovy installation lib directory).  I also needed to include the classpath entries within quotes to make it work properly.

Had I not included the Groovy JAR in the classpath for the java launcher, I would see an error like this:

java.lang.NoClassDefFoundError: groovy/lang/Script
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Caused by: java.lang.ClassNotFoundException: groovy.lang.Script
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 12 more
Could not find the main class: helloToWorld. Program will exit.
Exception in thread "main"

Had I not included the classpath in quotes, the error looks like this:

java.lang.NoClassDefFoundError: Files\Groovy\Groovy-1/7/4\lib\*
Caused by: java.lang.ClassNotFoundException: Files\Groovy\Groovy-1.7.4\lib\*
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: Files\Groovy\Groovy-1.7.4\lib\*. Program will exit.
Exception in thread "main"

In the examples above, the Groovy source (one line) was much shorter than the Java source code. Notice that the respectively compiled .class files, however, are much different in their relative size.  As the last screen snapshot demonstrated, the helloToWorld.class file generated with groovyc is 7524 bytes compared to the 703 bytes of the HelloWorld.class generated with javac.  The javap command is useful here to explain the difference in compiled sizes.  The output from running javap against the respective disassembled .class files is shown next.

javap-Disassembled javac-Generated HelloWorld.class File

Compiled from "HelloWorld.java"
public class HelloWorld extends java.lang.Object{
public HelloWorld();
public static void main(java.lang.String[]);
}

javap-Disassembled groovyc-Generated helloToWorld.class File

Compiled from "helloToWorld.groovy"
public class helloToWorld extends groovy.lang.Script{
public static java.lang.Long __timeStamp;
public static java.lang.Long __timeStamp__239_neverHappen1283320660787;
public helloToWorld();
public helloToWorld(groovy.lang.Binding);
public static void main(java.lang.String[]);
public java.lang.Object run();
public java.lang.Object this$dist$invoke$4(java.lang.String, java.lang.Object);
public void this$dist$set$4(java.lang.String, java.lang.Object);
public java.lang.Object this$dist$get$4(java.lang.String);
protected groovy.lang.MetaClass $getStaticMetaClass();
static {};
public java.lang.Object super$3$getProperty(java.lang.String);
public java.lang.String super$1$toString();
public void super$3$setProperty(java.lang.String, java.lang.Object);
public void super$1$notify();
public void super$3$println();
public void super$1$notifyAll();
public void super$3$print(java.lang.Object);
public void super$3$printf(java.lang.String, java.lang.Object[]);
public java.lang.Object super$1$clone();
public java.lang.Object super$3$evaluate(java.lang.String);
public void super$1$wait();
public groovy.lang.MetaClass super$2$getMetaClass();
public void super$1$wait(long, int);
public void super$2$setMetaClass(groovy.lang.MetaClass);
public java.lang.Class super$1$getClass();
public groovy.lang.Binding super$3$getBinding();
public void super$1$finalize();
public void super$3$printf(java.lang.String, java.lang.Object);
public void super$3$setBinding(groovy.lang.Binding);
public void super$1$wait(long);
public void super$3$run(java.io.File, java.lang.String[]);
public java.lang.Object super$3$evaluate(java.io.File);
public void super$3$println(java.lang.Object);
public boolean super$1$equals(java.lang.Object);
public java.lang.Object super$3$invokeMethod(java.lang.String, java.lang.Object);
public int super$1$hashCode();
static java.lang.Class class$(java.lang.String);
}

As the output from the javap class disassembler demonstrates, the shorter Groovy code translates to a much larger .class file because of all the support that must go into it to provide that Groovy magic.

The groovyc compiler is a necessity for compiling Groovy and Java together simultaneously.  It can also be useful for compiling .class files to execute without need for recompilation every time the script is run.  Finally, groovyc‘s output provides insight into the magic behind Groovy for those who are interested.  If nothing else, using groovyc explicitly also helps one realize how much is done automatically by the groovy native launcher.

This entry was posted in Groovy, Java (General), Syndicated. Bookmark the permalink.

Comments are closed.