The Sharat's

The Jython Pillow Guide

This is a document with tips and usage details about Jython that I’ve come across. I intend to document handy features of Python as well as some clever inter-op facilities provided by Jython.

I’m going to assume you’re not a complete beginner to Java and Python languages. If you find anything off or have a suggestion to add, please do write to me. Thanks!

Logging and Printing

When using Apache’s log4j, we can get an instance of a Logger using the API just as we would in Java:

>>> from org.apache.log4j import Logger
>>> log = Logger.getLogger('jython_script')

When getting a Logger instance for a module that is imported, a logger with a category specific to that module can be obtained using the following code:

log = Logger.getLogger(__name__)

The __name__ name is a variable containing the current module’s name as a string. Note that __name__ is set to the string '__main__' if the module is run as a script and not imported from another script. This should be kept in mind when using the above code.

The standard printing functions of Java can be imported into Python and used directly in the following way:

>>> from java.lang import System
>>> System.out.println('Hola')
Hola
>>> System.err.println('Hello there')
Hello there
>>> System.out.print('Hola\n')
Hola

However, it’s usually more convenient to use Python’s print statement to output things to standard output and error:

print 'Hello world!'

Here’s a table illustrating the print statement equivalents of the Java print* functions:

Java Python
System.out.println("!") print '!'
System.out.print("!") print '!',
System.err.println("!") print >> sys.stderr, '!'
System.err.print("!") print >> sys.stderr, '!',

Bean Properties

Jython can implicitly call the .get* and .set* methods that are widely used in Java classes to get and set the values of instance attributes. Here’s an illustration of how this inter-op works:

Jython Java equivalent
obj.somePropertyValue obj.getSomePropertyValue()
obj.somePropertyValue = 123 obj.setSomePropertyValue(123)

Of course, when such .get* and .set* methods are not available, this falls back gracefully to trying get/set the property values directly, just as Java would treat those statements.

Strings

Strings in Java (i.e., objects of type java.lang.String) are converted to unicode objects when passed in to Python world. Whereas str and unicode objects in Python are converted to java.lang.String instances when passed in to Java world. This conversion is seamless and we usually don’t have to worry about it.

However, if needed, we can explicitly create an instance of java.lang.String from a unicode object in Python:

>>> from java.lang import String
>>> greeting = String('Hello')
>>> greeting
Hello
>>> type(greeting)
<type 'java.lang.String'>

String formatting using % operator in Python cannot be applied to Java String objects. They have to converted to str or unicode first.

Maps as Dictionaries

For the purposes of the following examples, let’s work with the following Map:

java.util.Map<String, Integer> data = new java.util.HashMap<>();
data.put("a", 1);
data.put("b", 2);
data.put("c", 3);

Maps support the getitem syntax very well so it is usually convenient to think of them as python-style dictionaries. Here’s an example:

>>> print data['a']  # data.get("a")
1
>>> print data['b']  # data.get("b")
2
>>> data['d'] = 4  # data.put("d", 4)
>>> data['d']  # data.get("d")
4
>>> len(data)  # data.size()
4
>>> 'c' in data  # data.containsKey("c")
True
>>> del data['c']  # data.remove("c")
>>> 'c' in data  # data.containsKey("c")
False
>>> data
{a=1, b=2, d=4}
>>> len(data)  # data.size()
3

Although this resembles the usage of a traditional python dictionary, the methods you’d expect in a dictionary are not all available. This is a Map object after all and it has the methods of the Map class. However, it is easy to get see the parallels among some of the most used methods.

dict method Map method
.keys .keySet
.values .values
.clear .clear
.items (gives 2-tuples) .entrySet (gives Entry objects with .key and .value)
.update .putAll (accepts dict as well as a Map)

The dict builtin can be called on the Map object to get a python-style dictionary, if needed. Additionally, just like a python dictionary, calling list (or set) on the Map object gives a list (or set) of the keys in the Map.

Using for loops to iterate over Maps yields the keys in the Map, which is consistent with how for loops work with python dictionaries.

for key in data:
    print key, data[key]

Prints the following:

a 1
b 2
d 4

In python, the .items method returns each entry as a tuple which lets us write the for loop like the following:

# !!! Only works if `data` is a python-style dictionary, not if it is a `Map`.
for key, value in data.items():
    print key, value

But unfortunately, since Map doesn’t have the .items method, this is not possible. However, we can use the .entrySet method to construct something slightly similar.

for entry in data.entrySet():
    print entry.key, entry.value

To iterate over the values of a Map, since the method is called .values in both dict and Map, the same piece of code would work with any object.

for value in data.values():
    print value

Empty Map objects are treated as False in boolean contexts, just as with python’s dictionaries.

Collections

The two main collection types in Python are list and set. The equivalents in java are the interfaces List and Set. Let’s prepare some data for our examples.

java.util.List<String> planets = new java.util.ArrayList<>();
planets.add("Mercury");
planets.add("Venus");
planets.add("Earth");

java.util.Set<String> colors = new java.util.HashSet<>();
colors.add("White");
colors.add("Black");
colors.add("Red");
colors.add("Green");
colors.add("Blue");

The getitem syntax can be used with Lists seamlessly:

>>> planets[0]
u'Mercury'
>>> planets[1]
u'Venus'

The slicing syntax, returns Lists of the same type, not python-style lists.

>>> planets[:2]
[Mercury, Venus]
>>> type(_)  # `_` is a variable set to the return value of last expression.
<type 'java.util.ArrayList'>
>>> planets[::-1]
[Earth, Venus, Mercury]
>>> type(_)
<type 'java.util.ArrayList'>

However, the getitem syntax is not supported for Sets as it doesn’t make sense there since Sets are unordered collections. But the operator support available for sets in python are available with Java Set objects as well.

>>> 'Red' in colors
True
>>> len(colors)
5

The for loop can be used on any Collection type objects to iterate over the object’s contents.

>>> for x in planets:
...     print x
...
Mercury
Venus
Earth
>>> for x in enumerate(planets):
...     print x
...
(0, u'Mercury')
(1, u'Venus')
(2, u'Earth')

Here’s equivalents for some of the methods available in Java’s Collections and Python’s collection types.

Java Jython
Collection.add list.append / set.add
Collection.addAll list.extend / set.update (Prefer list + list or set.union)
Collection.contains in list or in set
Collection.isEmpty bool(list) or bool(set) (Can be used directly in a boolean context)
Collection.size len(list) or len(set)

Empty Collections are treated as False in boolean contexts, just as with python’s collections.

Java Arrays

Just as Java’s List is mirrored in Python with list, Java’s arrays are mirrored using the array structure available in Jython’s array module. That official documentation is quite exhaustive on this topic, so I suggest going over it to get an idea of handling arrays in Jython.

The Iteration Protocol

Java’s Iterator style iteration is supported by Jython’s for statements. For example, consider the following Java Iterator that’s trying to emulate a small fraction of Python’s range function:

package ssk.experiments;
import java.util.Iterator;

public class RangeIterator implements Iterator<Integer> {
    private Integer current = 0, max;
    public RangeIterator(int max) { this.max = max; }
    @Override
    public boolean hasNext() { return current < max; }
    @Override
    public Integer next() { return current++; }
}

Since classes are instantiated without a new keyword in Python, combined with the fact that Jython’s for statement supports Java’s Iterators, we can use the above in the following way:

from ssk.experiments import RangeIterator


for n in RangeIterator(5):
    print n

This gives the following output:

0
1
2
3
4

Since Jython’s for statement supports iterating over Java’s Enumeration type, the above same for loop would work with a RangeEnumeration class as defined below:

package ssk.experiments;
import java.util.Enumeration;

public class RangeEnumeration implements Enumeration<Integer> {
    private Integer current = 0, max;
    public RangeEnumeration(int max) { this.max = max; }
    @Override
    public boolean hasMoreElements() { return current < max; }
    @Override
    public Integer nextElement() { return current++; }
}

Jython seamlessly handles the getting of an instance of an Iterator from a Java Iterable. This is actually how the for statement works with the List and Set collections discussed earlier (Collection is a sub-interface of Iterable).

Patching Java Classes

In Python, new methods and attributes can be added to existing classes. This comes from the dynamic nature of the programming language and the runtime. The JVM is also a dynamic runtime, but the Java language doesn’t allow us to modify existing classes. This is where Jython comes in. Jython lets us add and override methods on existing Java classes. Although this is seldom needed, this can illustrate the extent of Jython’s integration with the JVM.

Here’s a Java class:

package ssk.experiments;
import java.util.List;

public class Country {
    private String name;
    public Country(String name) { this.name = name; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

There’s nothing fancy with the above class. It’s a regular class with one property with a .get and .set methods. Now, let’s add a new method to this class.

from ssk.experiments import Country


def upcase(self):
    self.name = self.name.upper()


Country.upcase = upcase

# Create a `Country` object and call `upper_name` method.
largest_country = Country('Russia')
largest_country.upcase()
print largest_country.name

This would print RUSSIA, as expected.

Note that this is an advanced feature and should be used with caution. In almost all cases, it is probably a better idea to modify the original Java class definition directly. But when that is not an option, creating a simple Python function that works with these objects should be considered. Modifying existing classes should only be used as a last resort.

Operator Overloading

One nice and practical case for adding methods on existing Java classes is to leverage Python’s support for operator overloading with Java classes. One good example for this is with the BigDecimal class. Mathematical operations on objects of BigDecimal are provided as individual methods like .add, .subtract etc. We can add operator support (in Jython) for these objects by adding the appropriate methods to the BigDecimal class.

For instance, here’s how we can add support for the + operator:

from java.math import BigDecimal

BigDecimal.__add__ = lambda self, other: self.add(other)

print BigDecimal(42) + BigDecimal(10)

This would print 52, as expected. More methods can be added to support all the mathematical operators such as __sub__ for subtraction and __mul__ for multiplication etc. The full list of such method names can be found on the official data model documentation page.

Conclusion

This is not intended to be an exhaustive guide to what Jython can do. I hoped to give you a taste of how well Jython handles inter-op with Java and hopefully I’ve helped you write better Python - Java inter-op code. Thank you and any suggestions and feedback are very welcome.