About Python-based libraries for Processing

  • Jython code can be compiled & compressed as a “.jar” file indeed.
  • But we also have to consider how a Java code would see & use a Jython class.
  • In Java all classes implicitly inherits from class Object:
  • Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html
  • But in Jython, if we don’t specify, a class doesn’t inherit from any class by default.
  • From now on, everything I say is pure speculation, b/c I’ve never seen a Jython coded library yet.
  • So in order to be on the safer side, any exposed class should inherit from an already existing Java class or in the very least from the Object class.
  • That is, the 1 w/ capital “O”, not Jython’s object w/ lowercase “o”:
from java.lang import Object

class JythonClass(Object): pass
  • AFAIK, everything in Jython is a PyObject:
    PyObject (Jython API documentation)
  • Therefore anything we return from a Jython method is gonna be by default a PyObject derived datatype.
  • That surely wouldn’t be very practical for some1 using such a Jython class from within their Java code.
  • So this Jython class below:
from java.lang import Object

class JythonClass(Object):
    def __init__(self, someValue): self.val = someValue


    def intAdd(self, someValue):
        self.val += someValue
        return self.val


    def floatAdd(self, someValue):
        self.val += someValue
        return self.val * 1.0


    def strAdd(self, someValue):
        self.val += someValue
        return `self.val`


    def listAdd(self, someValue):
        self.val += someValue
        return [self.val]


    def toString(self): return `self.val`
  • I believe it would probably become something like this when accessed from the Java side:
import org.python.core.*;

public static class JythonClass {
  public int val;

  public JythonClass(int someValue) {
    val = someValue;
  }

  PyInteger intAdd(int someValue) {
    val += someValue;
    return new PyInteger(val);
  }

  PyFloat floatAdd(int someValue) {
    val += someValue;
    return new PyFloat(val);
  }

  PyString strAdd(int someValue) {
    val += someValue;
    return new PyString(str(val));
  }

  PyList listAdd(int someValue) {
    val += someValue;
    PyList pl = new PyList();
    pl.append(new PyInteger(val));
    return pl;
  }
  • That would demand more effort for the Java programmer to convert the returned datatype to another 1 more familiar:
    int intVal = jython.intAdd(50).asInt(); // explicit conversion method call
  • The method above intAdd() would probably return datatype PyInteger, not a Java primitive int:
    PyInteger (Jython API documentation)
  • So a Java programmer would need to know that a call to asInt() is necessary in order to store method intAdd()'s returned value to a Java int variable:
    PyInteger (Jython API documentation)
  • As a workaround we can convert a Jython datatype to a more common Java 1 before returning a value from a method:
from java.lang import Object, Integer, Float, String
from java.util import ArrayList

class JythonClassWorkaround(Object):
    def __init__(self, someValue): self.val = someValue


    def IntegerAdd(self, someValue):
        self.val += someValue
        return Integer(self.val)


    def FloatAdd(self, someValue):
        self.val += someValue
        return Float(self.val)


    def StringAdd(self, someValue):
        self.val += someValue
        return String(`self.val`)


    def ArrayListAdd(self, someValue):
        self.val += someValue
        return ArrayList([self.val])


    def toString(self): return String(`self.val`)
  • The class JythonClassWorkaround above would be much easier for a Java programmer IMO.
  • Probably it would be seen as something like this in Java:
import org.python.core.*;

public static class JythonClassWorkaround {
  public int val;

  public JythonClassWorkaround(int someValue) {
    val = someValue;
  }

  Integer IntegerAdd(int someValue) {
    val += someValue;
    return new Integer(val);
  }

  Float FloatAdd(int someValue) {
    val += someValue;
    return new Float(val);
  }

  String StringAdd(int someValue) {
    val += someValue;
    return new String(str(val));
  }

  ArrayList<Integer> ArrayListAdd(int someValue) {
    val += someValue;
    ArrayList<Integer> al = new ArrayList<Integer>(1);
    al.add(new Integer(val));
    return al;
  }

  String toString() {
    return new String(str(val));
  }
}
  • Here’s a Java test-drive for both classes:
import org.python.core.*;

JythonClass jython = new JythonClass(100);
JythonClassWorkaround jyJava = new JythonClassWorkaround(100);

int intVal;
float floatVal;
String strVal;
ArrayList<Integer> listVal;

void setup() {
  println(jython, jyJava); // 100 100

  intVal = jython.intAdd(50).asInt(); // explicit conversion method call
  println(intVal); // 150

  intVal = jyJava.IntegerAdd(-70); // auto-unboxing
  println(intVal); // 30

  floatVal = (float) jython.floatAdd(-30).asDouble(); // conversion method
  println(floatVal); // 120.0

  floatVal = jyJava.FloatAdd(20); // auto-unboxing
  println(floatVal); // 50.0

  strVal = jython.strAdd(-45).toString(); // explicit conversion method call
  println(strVal); // 75

  strVal = jyJava.StringAdd(10); // already a Java string
  println(strVal); // 60

  listVal = new ArrayList<Integer>(jython.listAdd(-35));
  println(listVal); // [40]

  listVal = jyJava.ArrayListAdd(23);
  println(listVal); // [83]

  exit();
}

P.S.: Jython’s javadoc: jython 2.7.3 javadoc (org.python)

2 Likes