ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Tips for Scripting Java with Jython
Pages: 1, 2

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.