The JVM Fanboy Blog 

Running Nashorn scripts in Ant build scripts: The basics

by vincent


Posted on Tuesday Dec 01, 2015 at 09:01AM in Build Tools


When I start a Java project that I think can confirm to the rules of Apache Maven, I use Maven to create build scripts. Nowadays this is in the majority of my web projects.

Occasionally though, there are cases where I want full control of every step and/or want to do a lot of exotic steps. In those (rare) cases, I still manually create Apache Ant XML build scripts. It has so many built-in type of tasks, most of which are easy to use. Unlike many other developers I know, I quite like Ant, especially when also using Apache Ivy for dependency management.

Checking out the new popular choice for building JVM projects, Gradle By Gradle, Inc., is another high entry on my ever -growing to-do list. Gotta love a tool that has a cursing elephant as a mascot, to illustrate the usual building frustrations ;-) . I will definitely check Gradle out soon.

As probably well known by now, I am a huge Oracle Nashorn fan. When I started working on my latest project, I figured it could be handy to run Nashorn scripts inside Ant scripts and found multiple solutions that I'd like to discuss. For now let's start with the most simple method.

Script Task

Nashorn is fully compatible with the JSR-223 (aka "Scripting for the Java Platform" standard), which Ant supports. Several enhancements were done in Ant 1.7 to this task, so I assume you use a somewhat recent Ant version.

To simply run Nashorn scripts as part of a Ant target, you can use the <script> task. You can embed the script directly in the build.xml file (yuck!) or point it to an external file containing the script.

A simple build.xml example that embeds the script in the XML file (something that I'd never do in production!)

<?xml version="1.0" encoding="utf-8"?>
<project name="VincentsProject" basedir="." default="main">

	<property name="message" value="Hello!"/>
	
	<target name="main">
		<script language="nashorn" > <![CDATA[
			print(message);
			print(project.getProperty("message"));
			print;
			print(project.name);
			print(VincentsProject.name);
			print;
			project.log("Logged from script", project.MSG_INFO);			
		]]></script>
	</target>
</project>
    

You can run the script by saving above's text in a "build.xml" file, switch to a terminal window (Command Prompt on Windows) and run "ant". The output should be something like:

Console output example

Consult Ant's Script task documentation and note some things here:

  • It would have been much, much better to store the script in an external file in a subdirectory and add a src="./build_scripts/script1.js" alike attribute to your <script> attribute.

  • Ant makes available all defined properties to the external script. That's why
    print(message), print(project.getProperty("message")) and print(VincentsProject.name)
    lines all work. You can disable this behavior by adding the setbeans=false attribute to the <script> element, in that case only the "project" and " self" variables would have been passed to the script and "VincentsProject" and "message" would not have been available.

  • You could use the language="javascript" attribute in the <script> element, but this would run Rhino on Java versions 1.6 and 1.7. It is very likely your Nashorn JavaScript script will not be compatible with Rhino, so I'd recommend to use language="nashorn" attribute, unless you are sure your script is compatible with both, or your project requires Java 1.8 or later anyway.

  • Don't worry about the "manager" attribute. Its default value "auto" should be fine. Or set it to "javax" if you're a purist. From what I understand, Apache BSF was an older scripting standard that predates and inspired the JavaX JSR-223 specification that Nashorn implements.

  • When your Nashorn script uses external Java libraries, you can add a "<classpath>" element to the <script> element, like: <classpath><fileset dir="lib" includes="*.jar" /></classpath>

  • You can also add a classpath by defining a "<path>" element in your build file under "<project>" element; and refer to this inside your script element by using the "classref" attribute. See Ant documentation for more help. Use this construction if you need the same classpath specification for multiple tasks.

  • One thing that not seems possible is to add parameters to the ScriptFactory. AFAIK it's therefore not possible to use Nashorn's shell scripting capabilities when using this Script task.

Note that you can do some funky stuff. You can implement a full Ant task that takes file sets as a parameter. I'll rewrite one of the examples from the Ant documentation in Nashorn and post it here.

In a next post about this subject, I will post about the Scriptdef task, that adds some interesting features.



No one has commented yet.
Comments are closed for this entry.