Jython & Java: the whole is greater than the sum of the parts
 

Jython is a Java Virtual Machine (JVM) implementation of Python.

Python is a high level, general purpose programming language.  It supports list processing, regular expressions, multi-threading, complex numbers and a host of other advanced features in a late binding, multiple-inheritance object-oriented environment.  It can run interpreted or be compiled.  It can run stand-alone, call C programs, or be called from C.  Python's clean and simple syntax make it easy to read, easy to learn, and is often used for beginning programming classes.  At the same time, Python is robust, fully featured, and frequently the language of choice for graduate computer science courses.  Python's closest cousin is Ruby; Perl and Tcl have similarities. 

Jython is a 100% Java implementation making it portable to wherever JVMs are found.  Jython can subclass and instantiate Java classes, and Jython classes can be accessed from Java programs.  In addition, Java can easily invoke the Jython interpreter to run other source codes at run time.  Java compiled byte codes comply with all the Java security mechanisms making for secure client-side applets written in Python. 

What follows are brief introductions on how to install Jython, call Java classes, and access Jython codes from Java.  You will also find an annotated list of additional references. 

Contents:
    Jython Installation
    Call Java classes from Jython programs
    Call Jython classes from Java
    Run Python code from Java
    Appendix A:  RunPython.java
    Appendix B:  Jython References

 
Jython Installation

These instructions are specific to Windows 95/98/NT platforms and assume Java v1.2 or later is already installed (Java's java.exe and rt.jar files are findable via the PATH and CLASSPATH variables respectively).  *nix users should adapt appropriately. 

The Jython installer is a Java .class file.  The latest installer is "jython-21.class" and can be downloaded from the Jython web site.  Install Jython by typing

java jython-21
An installer window will ask where Jython is to be installed.  Any location is acceptable, but C:\Jython21 is a good choice. 

Upon completion, be sure you have C:\Jython21 in your PATH and CLASSPATH environment variables so Jython.bat, Jythonc.bat and jython.jar are visible.  Windows 9x users may want to modify autoexec.bat to look something like the following.

 SET WINPATH=C:\windows;C:\windows\command
 SET JAVAPATH=C:\jdk1.4.0\bin
 SET JythonPATH=C:\Jython21;C:\Jython21\Lib
 SET PATH=.;%JAVAPATH%;%JythonPATH%;C:\Python;%WINPATH%

 SET JAVACLASSPATH=C:\jdk1.4.0\jre\lib
 SET JythonCLASSPATH=C:\Jython21
 SET CLASSPATH=.;%JAVACLASSPATH%;%JythonCLASSPATH%

(Putting a copy of jython.jar in the same directory as rt.jar avoids the CLASSPATH issue.)


How to call Java classes from Jython programs

The most common use of Jython is the quick access of Java classes in a RAD or prototyping environment.  Here is a very simple example using both Python (os.getcwd) and Java Swing (JFileChooser) library calls. 

# file: simpleJy.py

from javax.swing import JFileChooser
from java.io import File
import os, sys

def chooseFile(cwd=''):
    chooser = JFileChooser()
    chooser.setCurrentDirectory(File(cwd))
    returnVal = chooser.showOpenDialog(None)
    if returnVal == JFileChooser.APPROVE_OPTION:
        return chooser.getSelectedFile().getPath()  # or perhaps .getName()
    return ''

if __name__ == '__main__':
    filepath = chooseFile(os.getcwd())
    if filepath:
        print filepath
    else:
        print '<< no file selected >>'

    sys.exit()

Run this code from a command line by typing

jython simpleJy.py


How to create Jython classes callable from Java programs

A Jython class is a Python class with the restriction that it be single inheritance and the doc string be a Java signature.  Only those classes to be called from Java are so affected; all of the remaining Jython code is unchanged. 

Write and test as much of your program as possible as a pure Python program.  This is optional, but it is usually quicker than launching the JVM each time you want to run a test. 

Then modify and test your Python code as a Jython class.  This should not be difficult, but here are a few things to note. 

  1. Be sure you import java, and as necessary, javax and other packages. 
  2.     import java
        import javax

  3. The Jython class must inherit from a Java class.  It may be java.lang.Object, or another if you wish to inherit behavior. It is best if you use fully qualified Java class names.
  4.     class MyFrame(javax.swing.JFrame):   or...
        class MyFrame(JFrame):

  5. For those methods to be called from Java, there must be a Java signature so the Java compiler can know the proper data types.  Recall that Python allows a properly indented string to be a comment, or more properly, documentation, if it is the first statement in a method declaration.  Jython uses this string to be the Java signature if it begins with @sig.  In the following example there is only one argument, a Java string, and no return value.  Note the string begins with @sig and String has a fully qualified name.

        def doit(filename):
            "@sig public void doit(java.lang.String filename)"
            ...

    In this example there is a return argument, a Java Integer.

        def doit(filename):
            "@sig public java.lang.Integer doit(java.lang.String filename)"
            ...
            return someIntegerValue

  6. The .py files should be clean of test code.  Either comment out your test code or put the test code in a separate file that you will not submit to the Jython compiler. 
  7. Only the core Python libraries were ported to Jython and subsequently compiled into the jython.jar file.  Numerous other Python libraries are usable but you will have to first compile them to .class files.  (See the the Python documentation for a list of core and non-core modules.)

Compile the Jython code with jythonc from a command line. This may take a few seconds.  Typing jythonc --help will show you how to define packages and build .jar files.  (Yes, --help is not a valid switch, but it does trigger the usage output.)  If you use jythonc with no options, you will find your .class files in the jpywork subdir.  For example, if your module name is Sample and you type

    jythonc Sample

you should find Sample.java, Sample.class, and Sample$_PyInner.class in jpywork.  Move those .class files to somewhere in your CLASSPATH.

A Java program calling your new Jython classes might contain lines like...

    // file: TestSample

    import Sample;
    ...
    Sample samp = new Sample();
    samp.doit("test.txt");
    ...

If you are using an IDE, be sure to include rt.jar, jython.jar and the jpywork .class files in your project.

How to compile additional Python library modules

Go to your Python /lib directory and copy the .py files of interest to a working directory.  Compile each with jythonc and you should find the .class files in the jpywork subdirectory.  Move the .class files to your CLASSPATH or combine them into a .jar and move that to your CLASSPATH. 
NB: Python only modules can receive this treatment; modules calling compiled C/C++ code will not work. 


How to run Python programs from Java

An easy way to run Python programs from within Java is to invoke the Jython interpreter to run the Python code.  The Python programs require little or no modification.  Unlike all Java code which must be in OO methods, there is no such requirement for Python.  Procedural Python is fine. 

Start by writing and testing your Python program as a Python program.  Then include code, like that shown below, in your Java code.  It's quicker that way. 

In following example,  main instantiates a Jython interpreter, loads a value into num, runs sq.py, and extracts and prints the answer.  (Here everything runs in main, but that is not necessary.) 

    // file RunSqPy.java

    import org.python.util.PythonInterpreter;
    import org.python.core.*;

    public class RunSqPy {
        static public void main(String[] args) throws PyException {

            // instantiate the interpreter
            PythonInterpreter interp = new PythonInterpreter();

            // set runtime args as Jython global variables
            interp.set("num", new PyInteger(2));

            // cause the Python program to be run (a fully
            // qualified pathname is allowed)
            interp.execfile("sq.py");

            // get values
            PyObject sq  = interp.get("square");
            PyObject num = interp.get("num");

            // ...and do with them as you please (you may need
            // to cast them depending on usage)
            System.out.println("square of " + num + " is " + sq);
        }
    }

Compile this with javac RunSqPy.java, but before running it, be sure you have the file sq.py as shown below. 

    # file: sq.py

    # this could be a whole lot more sophisticated, but
    # this is sufficient to illustrate how to access
    # variables before and after execution.

    print '--- sq.py start ---'

    if __name__ == '__main__':
        num = 7

    print 'num =', num
    square = num**2
    print 'square =', square

    print '---- sq.py end ----'

Typing java RunSqPy should yield

    --- sq.py start ---
    num = 2
    square = 4
    ---- sq.py end ----
    square of 2 is 4
but typing python sq.py should give
    --- sq.py start ---
    num = 7
    square = 49
    ---- sq.py end ----

Remember, only the core Python libraries were ported to Jython.  You will have to make available any other Python modules you need. 

Compiling the Java code in Appendix A (RunPython.java) provides a general purpose Java class to facilitate the running of Python code.  This cleaner example does the same as RunSqPy.java above. 

    // file: ShortTestPython.java

    import RunPython.*;

    public class ShortTestPython {
        public static void main(String[] args) {
            RunPython py = new RunPython();
            py.setInt("num", 2);
            py.run("sq.py");
            System.out.println("square = " + py.getInt("square"));
        }
    }
Your Python program might want to have logic that can determine if it is running standalone (from a command line) or is being called from a Java program.  A simple declarative technique is
    if __name__ == '__main__':
        num = 7
If your code needs to run in multiple environments where the value of a variable can be set set in one of several ways, you will need some way of detecting whether it has already been set or not. The following example allows you to not give a value if the variable already has one.
    try:                 # if not already defined (fm Java), an
        junk = num       # exception will be thrown
    except:
        num = 7          # set a default value or inspect the
                         # command line arguments (sys.argv)

Appendix A:  RunPython.java

The use of this Java class, RunPython, is strictly optional, but it does simplifiy access to the Jython interpreter.

    import org.python.util.PythonInterpreter;
    import org.python.core.*;

    public class RunPython {

        // instantiate a fresh interpreter
        PythonInterpreter interp = new PythonInterpreter();

        // a 'do nothing' constructor
        public RunPython() { }

        // use this contructor if no variables to be passed
        // in and you want to run a Jython program (saves a line)
        public RunPython(String filename) {
            run(filename);
        }

        // run the named Jython program
        public void run(String filename){
            interp.execfile(filename);
        }

        // gets an integer return value
        public int getInt(String name) {
            return ((PyInteger) interp.get(name)).getValue();
        }

        // sets an input integer value
        public void setInt(String name, int value){
            interp.set(name, new PyInteger(value));
        }

        // gets a double return value (Python floats are doubles)
        public double getDouble(String name) {
            return ((PyFloat) interp.get(name)).getValue();
        }

        // sets an input double value (Python floats are doubles)
        public void setDouble(String name, double value){
            interp.set(name, new PyFloat(value));
        }

        // gets a string return value
        public String getStr(String name) {
            return ((PyString) interp.get(name)).toString();
        }

        // sets an input string value
        public void setStr(String name, String value){
            interp.set(name, new PyString(value));
        }

        // can add more getters and setters for complex,
        // list, dictionary, tuple, etc.   ...someday.
    }

Appendix B:  Jython References

An excellent book devoted entirely to Jython is "Jython Essentials" by Pedroni and Rappin, published by O'Reilly (ISBN 0596002475).

Mark Lutz devoted a section to Jpython (Jython) in his book "Programming Python", also published by O'Reilly (ISBN 0596158106).

"The Quick Python Book" also has a section about Jpython. The 1st edition was written by Harms and McDonald; the 2nd edition is by Ceder and Jones. (ISBN 193518220X).

"The Definitive Guide to Jython" is a free, open source, Creative Commons  online book.  It is also available in hard copy. (ISBN 1430225270).

And, there is some good information at the Jython web site.



Larry Bugbee, Last updated: 20-July-2016