Accessing Jython from Java Without Using jythonc

Submitted By: Josh Juneau

You may or may not know that it is possible to access Jython code from Java without compiling it using the jythonc utility. This technique is possible using a mixture of Java interfaces and usage of the PythonInterpreter. As a matter of fact, I believe that using this technique correctly is more effective than using jythonc.

To put it simply, to use this technique you must create a "factory" method which uses the PythonInterpreter class to interpret a .py module for use within Java code. Any Java code that uses the Jython code should be coded against an interface which is implemented by the Jython code.

In order to provide a fully functional example, I've created a simple application with hard-coded data. This application shows the potential for using this technique within your Java applications to have the ability for use of dynamic Jython objects.

The application is simply called "jyinterface" and it contains four pieces of code:

We'll start by coding the "EmployeeType.java" interface which is what our Java code will use in order to interact with the Jython object:

package jyinterface.interfaces;

public interface EmployeeType {
    
    public String getEmployeeFirst();
    public String getEmployeeLast();
    public String getEmployeeId();
    
}

The Jython bean "Employee.py" is just a simple Jython object which implements the Java interface "EmployeeType.java":

# Jython source file
from jyinterface.interfaces import EmployeeType

class Employee(EmployeeType):
   def __init__(self):
      self.first = "Josh"
      self.last  = "Juneau"
      self.id = "myempid"

   def getEmployeeFirst(self):
      return self.first

   def getEmployeeLast(self):
      return self.last

   def getEmployeeId(self):
      return self.id

Next, the most powerful code for this technique is the "JythonFactory.java" class. This code defines a method which interprets a Jython module into Java and returns for use within Java code. The best part about creating a factory class such as this one is reuse! The factory can be coded in many different ways, but this way allows for reuse because you can essentially pass any Java interface/Jython module to it.

package jyinterface.factory;

import org.python.util.PythonInterpreter;

public class JythonFactory {
   private static JythonFactory instance = null;
    
   public synchronized static JythonFactory getInstance(){
        if(instance == null){
            instance = new JythonFactory();
        }
        
        return instance;
              
    }
    
   public static Object getJythonObject(String interfaceName,
                                        String pathToJythonModule){
              
       Object javaInt = null;
       PythonInterpreter interpreter = new PythonInterpreter();
       interpreter.execfile(pathToJythonModule);
       String tempName = pathToJythonModule.substring(pathToJythonModule.lastIndexOf("/")+1);
       tempName = tempName.substring(0, tempName.indexOf("."));
       System.out.println(tempName);
       String instanceName = tempName.toLowerCase();
       String javaClassName = tempName.substring(0,1).toUpperCase() +
                           tempName.substring(1);
       String objectDef = "=" + javaClassName + "()";
       interpreter.exec(instanceName + objectDef);
        try {
           Class JavaInterface = Class.forName(interfaceName);
           javaInt = 
                interpreter.get(instanceName).__tojava__(JavaInterface);
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();  // Add logging here
        }

       return javaInt;
   }
}

As we stated previously, a Java interface/Jython module combo needs to be passed to the getJythonObject method in order to return the resulting code. In the following piece of code, you can see how this is done. Simply pass in two strings:

  1. Fully qualified name of the Java Interface
  2. Full path to the Jython code module

Here is the "Main.java" code:

package jyinterface;

import jyinterface.interfaces.EmployeeType;
import jyinterface.factory.JythonFactory;
import org.python.util.PythonInterpreter;


public class Main {
    
    EmployeeType et;
    
    /** Creates a new instance of Main */
    public Main() {
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        JythonFactory jf = JythonFactory.getInstance();
        EmployeeType eType = (EmployeeType) jf.getJythonObject(
                               "jyinterface.interfaces.EmployeeType", "<<path to module>>/Employee.py");
        System.out.println("Employee Name: " + eType.getEmployeeFirst() + " " + 
                    eType.getEmployeeLast());
        System.out.println("Employee ID: " + eType.getEmployeeId());
        
    }
}

This technique is powerful because it allows an application to use code which can be interchanged or dynamically updated without re-deployment or re-compile. It also follows a great Java practice which is code against Java interfaces!! One downfall to this approach is that the code is interpreted every time it is invoked, so the performance may not be as good as using a jythonc compiled piece of code. It obviously depends upon the requirements of the application, but the usefulness of this technique may outweigh the performance factor in many cases.

Next time you plan to create a Java application that contains some Jython code, give this technique a try...