ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Jython Essentials

Tips for Scripting Java with Jython

by Noel Rappin, co-author of Jython Essentials
03/27/2002

You have a programming dilemma.

Maybe you're writing a Java program, and you need to do a quick one-off script to clean up your database. Sure, you could write it in Java, but that can involve a lot of overhead for a quick script. You could write it in an outside scripting language, but you'd really like access to the business logic already in your Java program.

Or maybe you’re writing a servlet, and the requirements are changing quickly. Your data model is changing, and you're having trouble keeping all the type information consistent.

Or maybe you’re writing a standalone program, and you'd like to use the large variety of tools already written for Java, but you'd also like to use a tool that makes your program 25-50 percent shorter, and easier to write and maintain.

Jython is the tool for you.

Jython is a complete re-implementation of the Python programming language, written in 100 percent pure Java, which runs on any Java Virtual Machine (JVM). Python is a high-level, interpreted, object-oriented scripting language which combines elegant syntax rules with powerful built-in objects to create a language that is very easy to write, read, and maintain. Python is perhaps most notorious for its use of indentation to mark the beginning and end of statement blocks.

There are usually two reactions to this description of Jython. Some people ask, "Does it really work?"

It really works. Anything you can do with the Java SDK can be done in Jython, including standalone applications, applets, servlets, and beans. Arbitrary Java code can be called from Jython, Java objects can be used as-is, or can be subclassed in Jython. You can even write an object in Jython that can be used or subclassed by other Java code. In addition, nearly all of the modules of the standard Python library are available to be used from Jython.

Another common reaction is to ask why Jython is needed, since Java already exists. Java, like every programming language, is a tool, and it has its uses. But it can't be all things to all people. Outside of the Java world, you can use C/C++, Python, Perl, or any of dozens of other languages, each with its own strengths and weaknesses. Jython gives some of the same flexibility to the Java programmer.

Here are 11 specific features of Jython that can be particularly time-saving or exciting for Java programmers.

1. Interactive Interpreter

The Jython interpreter can run in an interactive mode. In this mode you can type in Jython code one line at a time and see the results. You can even interact with Java libraries via this interpreter. For example, if you type the following at the Jython prompt:

>>> import javax.swing as swing
>>> win = swing.JFrame("Welcome to Jython")
>>> win.size = (200, 200)
>>> win.show()

Jython will create a swing JFrame and display it on screen. You can continue to view and modify the attributes of the JFrame via the prompt. This can be tremendously useful during prototyping or while debugging. (You've probably noticed what seem to be some type inconsistencies in the third line of that code -- for more on that see tip #9).

2. Built-in Data Structures

The Jython analogues to Java's collection classes are much more tightly integrated into the core language, allowing for more concise descriptions and useful functionality. For example, notice the difference between the Java code:

map = new HashMap();
map.put("one",new Integer(1));
map.put("two",new Integer(2));
map.put("three",new Integer(3));

System.out.println(map.get("one"));

list = new LinkedList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));

and the Jython code:

map = {"one":1,"two":2,"three":3}
print map ["one"]
list = [1, 2, 3]

Jython's for statement is dependent on the list structures, so if you wanted to iterate over the above list, you would write it:

for i in list:

Which is just a bit simpler than the Java idiom for iterating over a list:

for (Iterator i; i.hasNext();) {
    i.next();
}

In Jython, the for statement will also automatically iterate over Java Lists, Arrays, Iterators, and Enumerators.

3. List Comprehensions

Jython offers list comprehensions, which are a cool shortcut for the common task of creating a list by applying a specific function to each element of an existing list. For example, in Jython you can write:

newList = [function(i) for i in oldList]

which is essentially equivalent to the Java code:

List newList = ArrayList()
for (Iterator i; i.hasNext();) {
    Object obj = i.next();
    newList.add(function(obj));
} 

List comprehensions can also provide a filter if only some of the items in the old list should be processed.

Jython Essentials

Related Reading

Jython Essentials
By Samuele Pedroni, Noel Rappin

4. Dynamic Variable Creation

In Jython, variables do not have to be declared before use, nor do their types need to be declared. (They do, however, have to be assigned before use). This is true both for local variables within a block, and for the data members of classes. Jython is, however, still strongly typed, and like Java, will not automatically cast variable types. Attempting to do something like:

1 + "1"

will raise an exception in Jython at runtime.

If you have never programmed in a dynamic language, it is understandable that the idea of not declaring variables or types may make you a little nervous. Programmers who switch to a dynamic language are often surprised by how rarely type errors actually occur in practice, and how quickly they are found and fixed when they do occur. When compared with the amount of effort spent in Java convincing the compiler that your program is legal, you may find that static typing may not always be worth the effort.

5. First Class Functions

In Jython, functions, methods, modules, and classes are all first class objects, which means they can be both passed to and returned from a function. This ability allows for some common programming tasks to be managed quite easily.

For example, suppose you have a complicated resource that needs to be opened, used, and closed in a variety of places, which might cause you to retype the open and close logic frequently. A simple example is a file. By passing the useful function as a parameter you can manage the resource in one place:

def fileLinesDo(fileName, lineFunc):
    file = open(fileName,'r')
    result = [lineFunc(each)for each in file.readlines()]
    file.close() 
    return result

The key here is that you don't have to rewrite the open and close statements each time you use the file, you can just call fileLinesDo. This is a trivial point for files, but if we added error checking or had a more complicated resource, it becomes very useful.

6. Dynamic Object-Oriented Typing

In Java, the legality of a method call such as obj.method() is calculated at compile time. Although this ensures that the method will exist at runtime, in practice it leads to a lot of time and effort spent on typecasts. It also creates lines of code such as this, where you know the line will be legal at runtime, but you still have to convince the compiler.

MyClass instance = (MyClass)list.get(2);

In Jython, the legality of obj.method() is determined at runtime based on the runtime type of the obj variable. In addition to removing the need for a typecast, this has several subtle benefits. Most importantly, it encourages reuse by making it easier to use an object of a different type in the existing code. This eliminates the need to define Java-style interfaces; instead you can just define the methods directly.

It also allows for old code to be used in ways not imagined when the code was written. Additionally, it makes Jython code much easier to unit test than Java code (and it also makes it easy to unit test Java code from Jython). In Jython, you can easily create a simple "mock object" that trivially responds to the methods of a hard- or expensive-to-create instance (such as a GUI or database), and use that to test your code.

7. Special Methods

Jython allows operator overloading in the form of specially named methods that can be defined on any object, and which are called by the interpreter, if they exist, when the corresponding core language function or operator is invoked.

Some of these are quite similar to Java functionality, such as the special method __str__, which is called when the object needs to be printed, and is equivalent to the Java toString(). Others, such as the __add__ method, are similar to operator overloading in C++. You can allow your instances to be accessible using array-like syntax using the __getitem__ and __setitem__ methods.

Other special methods allow an amazing amount of flexibility for your objects. The special method __getattr__ is called on any failed attribute lookup, and can be used, for example, to return a default value, or automatically redirect to a proxy object, or call a getter method. The special method __setattr__ is called on attribute assignment, and can be used, for example, to verify values, or to trivially broadcast changes to other interested objects. There is even a special method __call__, which allows your instances to be treated like functions.

8. Java Integration

Most of the features discussed above are features of the Python language, but Jython also has features that allow nearly transparent usage of existing Java code. Java packages can be imported into Jython as though they were Jython modules, and Java objects can be created using Jython object creation syntax. For the most part, you can use the Java objects in your Jython program exactly as though they were Jython objects (as shown in tip #1).

Jython classes can inherit from Java classes (Jython allows multiple inheritance of Jython classes, however no more than one Java class can be in the inheritance tree of a Jython object). The inheritance rules work essentially as you would expect -- the parent class Java methods are called if they are not overridden in the child class. If the parent class method is overloaded, Jython chooses the correct version of the method based on the signature of the arguments at runtime.

9. Bean Property Introspection

Jython uses introspection on Java objects to allow access to those objects in a more normal Python coding style. Python coders rarely use simple get and set methods, preferring to access the variable directly. Of course, Java style tends to encourage get and set methods. Jython introspection allows those calls to be made automatically. When Jython sees a line of code such as:

x = javaObj.attribute

it automatically generates a Java call of the method javaObj.getAttribute(), if such a method exists. Similarly, an assignment to javaObj.attribute is converted to a call to javaObj.setAttribute.

In addition, set methods can be automatically triggered from constructors by using a keyword argument. For example:

javax.swing.JProgressBar(stringPainted=1, foreground=color.green)

automatically invokes the setStringPainted() and setForeground() methods of the new JProgressBar instance -- even though the normal Java constructor for JProgressBar does not take arguments for these properties.

If the set method itself takes an instance argument, Jython lets you implicitly create an object of the needed class by placing the arguments to the constructor sequentially in a list on the right side of the assignment (technically, the structure in Jython is called a tuple, and is an immutable list). For example:

button.preferredSize = (300, 50)

calls the Java code

button.setPreferredSize(new Dimension(300, 50))

10. Event Listener Introspection

Jython also automatically performs introspection on event listener registration patterns and interfaces. When a Java class allows listeners to be registered for a bean event, Jython searches for the listener interface associated with that event.

When an instance of the class is created, Jython adds an additional attribute for each method defined by the interface. Since Jython has first class functions, you can directly assign a Jython function to those attributes, and Jython calls that function when the event is triggered. This allows you to replace Java inner classes with ordinary methods for responding to events.

The following Java code uses inner classes to terminate the program in response to a button push:

JButton close = new JButton("Close Me");
close.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt){
        java.lang.System.exit(0);
    }
});

The Jython equivalent uses Jython introspection to separate the function definition from the widget creation. It creates a separate function, terminateProgram(), and passes that to the JButton to be called when the action is performed. This code assumes that the JButton is defined inside a class.

close = swing.JButton("Close Me", actionPerformed=self.terminateProgram)

def terminateProgram(self, event):
    java.lang.System.exit(0)

The combination of property and event introspection makes Java libraries extremely easy to use from Jython. Swing code, for example, is significantly easier to read and manage because of the use of the Jython shortcuts.

11. Embedding

The easiest way to include Jython functionality into an existing Java program is to embed a Jython interpreter directly into the Java code. The Jython interpreter is a Java object, and an instance of the interpreter can be used within a Java program to evaluate Jython code. The Java program can interact with the Jython interpreter, and pass data back and forth between the two.

The embedded interpreter can be used to manage various kinds of customization of the parent program. For example, you could write a system management framework that allows users to define responses to system events in Jython. Property files could be written as live Jython modules. You could create programmatic filters with all the power of the Python language to enhance, for example, an email client. You could use Jython for macro functionality in nearly any kind of program, or as a mechanism to separate game logic from a game engine.

This is a very straightforward way of getting the benefits of Jython on an existing Java project. In fact, Jython servlets are written in this manner, with a pre-existing Java servlet which reads the Jython servlet in an embedded interpreter.

I hope this list has encouraged you to seek out Jython and try it on your JVM-based projects. For more information get a copy of Jython Essentials. Jython can be downloaded from Jython.org.

Noel Rappin has a Ph.D. in computer science from the Georgia Institute of Technology, where his research included methods for teaching Object-Oriented Programming and Design. He has extensive production experience in both Java and Python.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.