Scripting with Balance in Design and Performance Blog

Version 2


    We all know there are a variety of languages we can choose from, and that those languages could benefit your development process through features like dynamic typing or closures. There are a lot of resources on specific features of certain languages and how they make programming easier, cooler, and so on. But since you will probably use scripting to implement only portions of your Java applications, the important questions that are often neglected are when and how to use scripting in your applications.

    In this article, I'll try to explain some advanced concepts of the Scripting API and show how they could help you successfully use scripting in your Java applications.

    The basic prerequisite for any scripting language to be used in JVM is to have an interpreter (aka an "engine") accessible from Java. There are two common ways to achieve this: implement the engine in Java or make a Java wrapper around a native language interpreter. The features of scripting engines vary a great deal (we will come back to this later), but there are a few that represent a core functionality of every interpreter. Every engine has to be able to provide a context for scripts' evaluation and obviously has to be able evaluate scripts.

    In the simplest scenario, you will instantiate a scripting engine of some desired language in your Java application, bind some variables to provide the context to the engine, and at some point execute a script. Afterwards, you may also obtain some variable values from the engine context, as the values could be changed (or set) by the executed script.

    There's an obvious need for a framework that abstracts various scripting engines and thus creates general scripting support for Java applications. The Scripting API (javax.script) included in Java SE 6 serves just this purpose. It enables easy engine registration, instantiating engines through factory methods and sharing the context between them.

    In this article, I want to focus on something else. Many of the script engines available today provide more features to developers than just simple script evaluation. One such feature is the ability to call standalone functions and object methods defined in the script. In some languages you can even implement whole Java interfaces in scripts and use them in Java as regular objects. As we will see, these features can have a great impact on how you use scripting in your applications--but first, we must see how the Scripting API supports these features.


    One of the main design goals of the Scripting API was to be as generic as possible, so that a wide range of scripting engines could comply with it. For that reason, thejavax.script.ScriptEngine interface defines only the most basic operations of scripting engines: variable binding and script evaluation. All other advanced features that scripting engines could implement are encapsulated in separate interfaces, making it easy for developers to determine the characteristics of a certain engine and use it appropriately. This architecture also allows for the use of very simple engines through this API.


    In the following example, I will demonstrate theInvocable interface. First, let's create a simple script (all examples in this article will be implemented in JavaScript, so that the Rhino engine included in JDK 6 can be used to execute them):

    function sayHello(name) { println("Hello " + name); }

    This simple JavaScript example script, located in afunction.js file (and available in the Resources section at the end of this article), defines one function named sayHello that prints text to standard output. Now let's see how to invoke this kind of function using the Scripting API.

    package net.scriptinginjava.invocable; import; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class InvocableTest { public static void main(String[] args) throws Exception { ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("js"); if (engine instanceof Invocable) { engine .eval(new FileReader( "src/net/scriptinginjava/invocable/function.js")); ((Invocable) engine).invokeFunction("sayHello", "World"); } } }

    This Java application instantiates theScriptEngineManager class, uses the instance to obtain a desired script engine, and evaluates a script with it.

    The interesting part is the use of the Invocableinterface. As you can see, if the engine implements theInvocable interface, Java developers can use itsInvokeFunction method to call functions in previously evaluated scripts. This method accepts a function name as a first parameter and variable number of Object arguments (varargs) that will be passed as function arguments. In this example, the sayHello function is called and theWorld argument is passed to it. As a result, the "Hello World" text is printed to standard output.


    For object-oriented scripting languages, the same interface could be used to invoke methods on objects created in evaluated scripts. To demonstrate this feature, let's first create a suitable script (located in a method.js file):

    function Hello() {} Hello.prototype.sayHello = function(value) { with (this) println("Hello " + value); } var hello = new Hello(); hello.sayHello("World1");

    This script creates the Hello class with asayHello prototype function. Afterwards, it instantiates a hello variable and calls its method. As a result this scripts prints "Hello World1" on standard output.

    Now let's take a look at the following Java code.

    package net.scriptinginjava.invocable; import; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class MethodTest { public static void main(String[] args) throws Exception { ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("js"); if (engine instanceof Invocable) { engine .eval(new FileReader( "src/net/scriptinginjava/invocable/method.js")); ((Invocable) engine).invokeMethod(engine .get("hello"), "sayHello", "World2"); } } } 

    Again, the example looks much like previous Java program that evaluated the script and executed a function defined in it. The only difference is that this example uses theinvokeMethod method to call an object method. Remember the script we are using in this example: it instantiates ahello object. As such, it can be obtained from engine's context with the engine.get("hello")statement. That is exactly the first parameter that is passed to the invokeMethod method; an object defined in an evaluated script whose method we want to call. Other arguments are the same as for the invokeFunction method: the name of the method and variable number of objects to be passed as arguments to the method. In this example we called the sayHellomethod and passed World2 as the only argument. Since thesayHello method has been called twice (once from the script and once from the Java application), the application will print the following to standard output:

    Hello World1 Hello World2


    All examples shown above were nice and handy, but the real power of the Invocable interface is the fact it can be used to implement Java interfaces with scripts (of course, in languages whose engines support this feature). I'll get back to the discussion on why this feature is important and how you can benefit from it in your Java projects, but first let's demonstrate it with a simple example.

    Let's start by defining a simple Java interface:

    package net.scriptinginjava.invocable; public interface Hello { public void sayHello(String name); public void time(); }

    Now, remember our first JavaScript example used to demonstrate function calls with the Scripting API. It defines one function named sayHello, which accepts one argument. Let's see how we can use this simple script to implement the interface defined above.

    package net.scriptinginjava.invocable; import; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class InterfaceTest { public static void main(String[] args) throws Exception { ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("js"); if (engine instanceof Invocable) { engine .eval(new FileReader( "src/net/scriptinginjava/invocable/function.js")); Hello hello = ((Invocable)engine).getInterface(Hello.class); hello.sayHello("World"); //hello.time(); } } } 

    If you execute this Java application, you'll get "Hello World" text on your output, which mean that we managed to implement a interface with a three-line script.

    Now let's elaborate this example a bit further. The first interesting thing to notice it that the Rhino engine (used in this example) allows you to implement interfaces by providing scripts that define a collection of functions implementing interface methods. Further, in order to successfully implement an interface, you don't have to provide functions for all methods, just those that you are planning to use. In this example, we provided an implementation for the sayHello method and used it successfully from our Java application. You can experiment and uncomment the call to the time method, in which case you will get an exception stating that the time method is not implemented. Of course, if we now rewrite our script in the following manner:

    function sayHello(name) { println("Hello " + name); } function time() { println(new Date()); }

    and re-execute our Java application, we will get something like this

    Hello World Wed Aug 29 2007 14:53:16 GMT+0200 (CEST)

    Mechanisms for implementing Java interfaces vary from language to language and you should consult their documentation (or look at the Resources section for more reading on the topic) before trying to implement it with your scripting engine of choice. But one thing is common to all engines that support this feature: they enable easy and quick implementation of Java interfaces with suitable scripts.

    Practical Usage

    After this basic introduction to the Scripting API'sInvocable interface, it's time to see what kind of value it brings to the overall development process. Probably every Java developer is aware of the importance of interfaces and clean API designs. A design with interfaces approach to software development emphasizes separation of interfaces and their implementations and is one of the fundamental design techniques used in Java (and object-oriented programming in general).

    In order to define a part of your application as a software component or service and expose it for use either locally in your application or remotely, you need to define a well-structured interface. The primarily task of this interface is to define all operations that a componentshould implement. The particular implementations of the interface is a topic of its own and it is usually hidden from the end user of the component. Of course, many implementations of the same interface are possible, usually differing with regards to the context in which the component is used. This certainly leads to a much cleaner application design and (as we will see in a moment) is a base for many widely used design patterns.

    I'm sure that you have been aware of the aforementioned principles for years now, but the previous discussion is important in order to ask ourselves a crucial question: how does implementing Java interfaces with scripts and thejavax.script.Invocable interface enhance our development process? I don't want to debate here about dynamic typing, closures, runtime modifications, and all the other benefits that dynamic languages generally provide (you can find more on these topics in the Resources section). Here, I would like to talk about appropriate use of scripting in Java applications. As you've probably guessed, I think theInvocable interface has a big role in that.

    It easy to instantiate the script engine and evaluate scripts from certain points of your Java application. While this practice definitely has its place in development process, it is easy to break good object-oriented design with unstructured (or loosely structured) scripts. Your application most likely follow good object-oriented practices and follow many design patterns (IoC, for example), so you need a solution that will not break all the hard work that is put in to have a good overall application design. That is why the design with interfaces principle combined with interfaces implemented in scripts could lead to both good object-oriented designed software and rapid development with scripting languages.

    Of course, another important question involved in all discussions related to scripting is performance. If we implement some or most of our interfaces with scripts written in JavaScript or Groovy, how will this affect the performance of the overall solution? Luckily, there are mechanisms and patterns that can help us out with this problem.

    The ideal balance would be to have the flexibility of dynamic languages in the development phase, and pure Java performance in production. Fortunately, most of the scripting languages provide mechanisms that could be used to achieve this goal. The main one is the ability to compile your scripts to Java classes. After this process, you can use them to instantiate regular Java objects. Most of the "modern" script engines provide this functionality, but some of them (such as Groovy) go even a step further and define Ant tasks or Maven plugins that could be used in your build process.

    Now that we have both a script in evaluable source and its compiled version in our project, it is much easier to achieve our original goal. There are many ways you can instantiate a specific implementation of an interface, depending on whether certain conditions are met in the application. The one that I will demonstrate here is the well-known Factory Method pattern.

    In brief, it suggests that you should not instantiate your objects directly but to enclose this operation in a suitablefactory method and thus add more flexibility to the process. Let's say that we have a build environment in which our script that implements the Hello interface is compiled to the HelloImpl class. I will not dig into how this could be done in different environments, since it is beyond the scope of this article. Now look at the following Java example:

    package net.scriptinginjava.invocable; import; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class HelloFactory { private boolean debug = true; private ScriptEngine engine; public HelloFactory(boolean debug) { this.debug = debug; ScriptEngineManager factory = new ScriptEngineManager(); engine = factory.getEngineByName("js"); } public Hello getHello() throws Exception { if (debug) { System.out.println("scripted"); engine .eval(new FileReader( "src/net/scriptinginjava/invocable/interface.js")); return ((Invocable) engine) .getInterface(Hello.class); } else { System.out.println("compiled"); return new HelloImpl(); } } public static void main(String[] args) throws Exception { HelloFactory client = new HelloFactory(true); Hello hello = client.getHello(); hello.sayHello("World"); } }

    This Java class represents a factory that is responsible for instantiating implementations of the Hello interface. There are a few important things about this example. First, you can notice that this class has a debug property that is used to determine whether it should evaluate a script or instantiate a compiled object. This property is set through the class' constructor and used in the getHellomethod.

    Now if you run this example, you will get the following result:

    scripted Hello World

    meaning that we instantiated an object by evaluating a script. You can try to change the value of the debug parameter to false and see what happens. It will now print the following:

    compiled Hello World

    With this technique we have achieved our goal of having a dynamic environment to develop in and a pure-Java performance solution in production. Of course, a debug parameter is just a simple example and you will probably use a technique that is appropriate to your development environment (IoC framework, properties file configuration, etc.), but the main principle remains the same. You implement your interfaces with scripts and enjoy the flexibility of dynamic languages (such as the ability to modify your application at runtime). When finished, you compile your scripts and reconfigure the application to use the compiled implementation of the interfaces (a pure Java class).

    The design pattern that I just described above is a base for many scripting-based designed patterns that could be used in Java applications. There are many "traditional" design patterns whose elements are suitable for implementation in scripts (but you can also find patterns specific to the scripting environment). I discuss some of these patterns in chapter 8 of my book, Scripting in Java.


    When thinking about scripting languages in Java applications, two key questions come up: how it will affect software architecture and how will it affect performance. By keeping the design with interface principle as our focus and applying the simple patterns shown in this article, we can successfully tackle both of these questions. The rest is left to you to choose what language best suits your programming needs, but also when and how much you want to use scripting in your projects.