Scripting on the Java platform

Using Groovy, Jython, and JRuby for Java development

It has recently become popular to differentiate between the Java platform and the Java language, but many Java developers still are unsure of how to incorporate scripting into Java application development. In this article, Gregor Roth introduces you to scripting on the Java platform. Learn when and how to use scripts in your Java applications, whether you are gluing together various Java application modules with Groovy or Jython, or writing your first JRuby-based application for the Java platform.

As a Java developer, you may have noticed that the Java language is no longer the sole proprietor of the Java platform. Groovy is also a programming language for the Java platform, and innumerable other languages now have interpreters and compilers to run on top of the JVM. Among these, Jython and JRuby are two of the most popular. In addition, Java SE 6 includes built-in support for script engines, and JSR 223 defines a standard interface to interact with dynamic languages running on the Java platform.

In order to take advantage of the many possibilities opened up by scripting on the Java platform, you should clearly understand the challenges and benefits involved. You need to understand what happens when calling Java classes from scripts written in JRuby or Jython, and vice verse. You also need to be aware of the difficulties of integrating a scripting language into the Java platform, and what impact that will have on your development process. Finally, you should know the different characteristics of at least a handful of popular scripting languages, so that you can evaluate where they might fit into your programs.

This article presents an overview of what differentiates scripting languages such as Groovy, JRuby, and Jython from the Java language, discusses some of the challenges involved in scripting on the Java platform, and introduces you to the various ways you can integrate scripts originally written in Ruby or Python with your Java code, as well as some scenarios where doing so is useful.

Static versus dynamic typing

Most scripting languages are dynamically typed, whereas Java is a static-typed language. Static-typed languages require the type of a variable to be defined at declaration time, and the variable can only be set with the data of the declared type. In contrast, dynamically typed languages do not require the programmer to write explicit type declarations, because the type information is attached to values, not to variables. As you can see in Listing 1 the Groovy-defined variable v1 can be reset with values of different types at any time.

Listing 1. Dynamic typing in Groovy

def v1 = '66'      // sets the variable with a value of type String
println v1.dump()
// prints out:
// <java.lang.String@6c0 value=[6, 6] offset=0 count=2 hash=1728>

v1 = 9            // resets the variable with a value of type Integer
println v1.dump()
// prints out:
// <java.lang.Integer@9 value=9>

A typical implementation of a dynamically typed scripting language will keep the value of variables tagged with a type. This type will be checked immediately before using any value in an operation. The disadvantage of this approach is the need for extra processing cycles to determine the value type and to perform type checks at runtime. Advocates of static typing point out that using dynamic languages always leads to performance penalties.

Weak versus strong typing

Some popular scripting languages are weakly typed. Weakly typed languages allow operations on incompatible types. To do this, weakly typed languages support implicit type conversion or ad-hoc polymorphism. For example, Groovy allows you to do an add operation on an integer and string value, as shown in Listing 2.

Listing 2. Groovy-based example of weak typing

def v1 = '66'         // set v1 with a String typed value
def v2 = 5            // set v2 with a Integer typed value
def v3 = v1 + v2
println v3
// prints out: 
// 665

Like Groovy, Python is also a dynamically typed language. But in contrast to Groovy, Python is strongly typed, so it won't support the above operation. Strong typing is much less lenient than weak typing, and prevents mixing operations between mismatched types. You can see this in Listing 3.

Listing 3. Python-based example of strongly typing

v1 = '66'              # set v1 with a String typed value
v2 = 5                 # set v2 with a Integer typed value
v3 = v1 + v2
# prints out:
# TypeError: cannot concatenate 'str' and 'int' objects

Using a static, strongly typed language like Java puts the strongest possible constraint on the type of object at declaration time. For example, if you want to implement a callback pattern in Java, you will start by writing a callback interface that defines the callback methods and declares the return type, as well as all the argument and exception types. The concrete callback implementation will be referenced and called using the interface shown in Listing 4.

Listing 4. A callback pattern implementation in Java

// the call back handler definition
        interface IDataHandler {
                public boolean onData(INonBlockingConnection nbc) throws IOException;
        }


        // the server receives data and performs the handler's call back method
        class MultithreadedServer {
                 private volatile boolean isRunning = true;
                 private IDataHandler dataHandler = null;

                // accepts only an object which implements the IDataHandler interface
                MultithreadedServer(IDataHandler dataHandler) {
                        this.dataHandler = dataHandler;
                }


                public void run() {
                       while (isRunning) {
                           // waiting for data
                           // ...
            
                           // ... and dispatch it
                           dataHandler.onData(nbc);
                       }
                }
        }


        // the call back implementation
        class SmtpProtocolHandler implements IDataHandler {
                public boolean onData(INonBlockingConnection nbc) throws IOException {
                     SmtpSession session = (SmtpSession) nbc.getAttachment();
                     //...
                }
        }

        MultithreadedServer server = new MultithreadedServer(new SmtpProtocolHandler());
        server.run();
1 2 3 4 5 Page 1
Page 1 of 5