Java is a great language. It has many positive attributes, however one thing java is not good for is fast development. Now that I’m older and a little more impatient, I prefer to work in dynamic languages largely because of their short feedback cycle and instant gratification. Over the last few years, there’s been a movement towards the ability to run other languages within the JVM. This makes a lot of sense with the JVM being arguably the best part of Java. It makes it possible to use a dynamic language but still get some of the robustness and scalability of Java. Languages like Jython, Jruby and Jaskel are Java implementations of dynamic and/or functional programming languages that run in the context of a JVM and share a really nifty naming convention.
These languages have been in development for a while but until recently my team has only dabbled with some of them mainly for testing purposes. I haven’t really considered them a viable option for the “if I could only write this in Ruby” problem until recently. Java 6 has made integration of these languages very clean and easy.
The simple scripting inside java is easily demonstrable using javascript since the javascript engine is built into Java 6.
/* hello_world.js */
println("Hello World, I'm javascript")
I am going to attempt to run this super complex javascript from inside the JVM. The first thing I’m going to do is create a new Java project using Maven.
mvn archetype:create -DgroupId=com.weromans -DartifactId=scripting
Since the standard maven archetype doesn’t include a place to keep my scripts, I’ll create the directory ./scripting/src/main/javascript, and copy my hello_world.js file into it.
Just because I’m curious, I would like to see what scripting engines my environment currently supports. As I’ve already stated, javascript is supported out of the box, but let’s go ahead and verify that I’m not just lying to you for fun.
Open up the scripting/scr/main/java/com/weromans/App.java file in your favorite editor or IDE (vi if you’re hardcore), and modify it to include the following:
package com.weromans;
import java.util.List;
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngineFactory;
public class App
{
public static void main( String[] args )
{
ScriptEngineManager manager = new ScriptEngineManager();
List<ScriptEngineFactory> factoryList = manager.getEngineFactories();
for (ScriptEngineFactory factory : factoryList) {
System.out.printf("Engine Name: %s, Language: %sn",
factory.getEngineName(),
factory.getLanguageName());
}
}
}
Let’s just give Maven a little more information about our project so we can compile and run it easily from the command line. Edit your pom file to include the maven-compiler-plugin and the exec-maven-plugin.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.weromans</groupId>
<artifactId>scripting</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>scripting</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.weromans.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Now just complie and run it:
$ mvn compile exec:java
You should see the following output:
[INFO] Scanning for projects…
[INFO] ————————————————————————
[INFO] Building scripting
[INFO] task-segment: [exec:java]
[INFO] ————————————————————————
[INFO] Preparing exec:java
[INFO] No goals needed for project – skipping
[INFO] [exec:java]
Engine Name: Mozilla Rhino, Language: ECMAScript
[INFO] ————————————————————————
[INFO] BUILD SUCCESSFUL
[INFO] ————————————————————————
[INFO] Total time: < 1 second
[INFO] Finished at: Fri Apr 17 14:14:45 EDT 2009
[INFO] Final Memory: 3M/6M
[INFO] ------------------------------------------------------------------------
the line Engine Name: Mozilla Rhino, Language: ECMAScript is your applications output and it show’s that the only engine name that is currently supported is Mozilla Rhino which is the javascript engine. Now let’s modify this thing to run our super complex hellow world javascript.
Open up the scripting/scr/main/java/com/weromans/App.java file in the hard core editor of your choice and modify it as follows:
package com.weromans;
import java.io.FileReader;
import java.io.FileNotFoundException;
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
public class App
{
public static void main( String[] args ) throws
FileNotFoundException,
ScriptException
{
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine javascriptEngine = manager.getEngineByName("javascript");
javascriptEngine.eval(
new FileReader("src/main/javascript/hello_world.js"));
}
}
Execute it again:
$ mvn compile exec:java
[INFO] Scanning for projects…
[INFO] ————————————————————————
[INFO] Building scripting
[INFO] task-segment: [exec:java]
[INFO] ————————————————————————
[INFO] Preparing exec:java
[INFO] No goals needed for project – skipping
[INFO] [exec:java]
This is hello from hello_world.js
[INFO] ————————————————————————
[INFO] BUILD SUCCESSFUL
[INFO] ————————————————————————
[INFO] Total time: < 1 second
[INFO] Finished at: Fri Apr 17 15:27:26 EDT 2009
[INFO] Final Memory: 3M/6M
[INFO] ------------------------------------------------------------------------
You can see the hello world output from your javascript. Congratulations, you've just done some scripting in the JVM. I know the title says Ruby in Java, but it also says part 1, so you'll just have to check out Ruby in Java with Maven – Part 2 for the ruby part.
