Wednesday, 28 November 2007

Compiling Python(Jython) and for Java

Another view: Jython is the extension language for Java.

Use jythonc. What is jythonc and what is its status?

jythonc transforms Python source code into Java source code then invokes a Java compiler to turn it into .class files. This allows Python to be integrated into Java in several places that regular Jython currently doesn't support. It also processes special annotations in docstrings on methods in Python code to determine the static type information to expose when turning a dynmically typed Python method into a statically typed Java method.

jythonc is unmaintained and will not be present in Jython-2.3. While jythonc handles all of the language features present in Jython 2.2, it doesn't support 2.3 features such as generators. As such, it is not recommended that new Jython projects make use of jythonc. It is only included in Jython-2.2 to support older users of jythonc and to allow access to a few features that are only provided by jythonc at the moment:

  1. Running in a JVM with a classloader that will not load dynamically created classes
  2. Declaring Java method signatures in Python code
  3. Loading Python classes dynamically from Java with Class.forName

While all of these features are planned for Jython-2.3, they are currently only available from jythonc. Most uses of the second feature, adding method declarations to docstrings, can be handled by declaring a Java interface to implement with a Python class. Each method in the Python implementation takes the types of the Java method it implements. Exposing the Python class as an instance of that type to Java code can be done as explained in Accessing Jython from Java Without Using jythonc and its followup, Simple and Efficient Jython Object Factories.

(See http://www.jython.org/Project/jythonc.html)

You can extend Java classes.

You can add (J)Python protocols to Java classes.

You will need to describe the signature of methods in order to make them callable from Java (in addition to Jython).

What jythonc does -- jythonc translates .py files into .java source code files, then compiles these to .class files.

With jythonc, you can also:

  • Compile Jython (.py) to Java class files (.class).

  • Compile Jython to Java source, then stop without compiling to .class files.

  • Use a Java compiler different from the default: javac. See the help from jythonc:

    --compiler path
    -C path
    Use a different compiler than `standard' javac. If this is set to
    `NONE' then compile ends with .java. Alternatively, you can set the
    property python.jpythonc.compiler in the registry.

    This option can also be set in your Jython registry file.

Java compatible classes - In order to implement a Java compatible class (that is, one that acts like a native Java class and can be called from Java), your Jython code must follow these rules:

  • Inherit from a Java class or interface.
  • Include only one class per module.
  • Give the Jython class and the source file that contains it the same name.
  • Place all code inside that Jython class.
  • Include method signature hints (called sig-strings) -- Add a @sig line in the doc-string for each method.

How to use jythonc:

  • Type jythonc --help for help.

  • Compile your Jython code with:

    jythonc mymodule.py
  • To get help for jythonc, type:

    $ jythonc --help

Some notes:

  • When your run jythonc, by default, the .java files are placed in a sub-directory ./jpywork. You can override this with the --workdir command line option. From jythonc --help:

    --workdir directory
    -w directory
    Specify working directory for compiler (default is ./jpywork)
  • When you run this resulting code from Java, the directory ./jpywork and the Jython jar file must be on your classpath.

Example -- The following Jython code extends a Java class. Compile it with jythonc:

# Foo.py

import java

class Foo(java.util.Date):
def __init__(self):
self.count = 0
def bar(self, incr=1):
"""@sig void bar(int incr)"""
self.count += incr
return self.count
def toString(self):
cnt = self.bar()
return "Foo[" + java.util.Date.toString(self) + " " + `cnt` + "]"

Example, continued -- Here is Java code to test the above. Compile it with javac and run it:

// FooTest.java

import Foo;

public class FooTest {
public static void main(String[] args) {
Foo foo = new Foo();
System.out.println(foo);
foo.bar();
foo.bar(43);
System.out.println(foo);
}
}

Notes:

  • Compile and run:

    $ javac FooTest.java
    $ java FooTest
  • You will need jpywork on your classpath. So, you can compile and run it as follows:

    $ ../../Jython-2.2a/jythonc Foo.py
    $ javac -classpath ../../Jython-2.2a/jython.jar:./jpywork FooTest.java
    $ java -classpath ../../Jython-2.2a/jython.jar:./jpywork FooTest

In order to implement a Java compatible class (that is, one that acts like a native Java class and can be called from Java), your Jython code must follow these rules:

  • Inherit from a Java class or interface.
  • Include method signature hints (called sig-strings).
  • Give the Jython class and the source file it is in the same name.

Here is another simple example:

"""simpleclass.py

This is a simple class to demonstrate the use of jythonc.
"""

import java.lang.Object

class simpleclass(java.lang.Object):
def __init__(self, name='The Horse With No Name'):
"""public simpleclass(String name)
"""
self.name = name
self.size = -1
def set_name(self, name):
"""@sig public void set_name(String name)
"""
self.name = name
def set_size(self, size):
"""@sig public void set_size(int size)
"""
self.size = size
def show(self):
"""@sig public String show()
"""
return 'name: %s size: %s' % (self.name, self.size, )

And, a Java test harness for this simple example:

// simpleclasstest.java

import simpleclass;

public class simpleclasstest {
public static void main(String[] args) {
String s1;
simpleclass sc = new simpleclass();
s1 = sc.show();
System.out.println("1. " + s1);
sc.set_name("dave");
sc.set_size(4321);
s1 = sc.show();
System.out.println("2. " + s1);
}
}

Notes:

  • In order to produce a Java compatible class, our Jython class must inherit from a Java class. In this case, we use java.lang.Object, because we do not need to inherit any behavior.
  • The methods set_name, set_size, and show each have sig-strings.

Put jpywork on your CLASSPATH, then use the following to compile and test the above:

$ jythonc simpleclass.py
$ javac simpleclasstest.java
$ java simpleclasstest
1. name: The Horse With No Name size: -1
2. name: dave size: 4321

In the following example, we create a stand-alone Jar file, that is, one that can be executed as a script on a machine where Jython is not installed. Here is the Jython script:

# test_jythonc.py

import sys

def test(words):
msgs = ['hi', 'bye']
for word in words:
msgs.append(word)
for msg in msgs:
print msg

def main():
args = sys.argv[1:]
test(args)

if __name__ == '__main__':
main()

Compile and build a Jar file with the following:

$ jythonc --all --jar mytest.jar test_jythonc.py

Run it as follows:

$ java -jar mytest.jar hello goodbye
hi
bye
hello
goodbye

Notes:

  • Note that our Jython script contains no class. jythonc will create a public class and a public static main function for us.
  • The --jar flag tells jythonc that we want the results placed in a Jar file (as opposed to placing it in the work directory ./jpywork).
  • The --all flag tells jythonc to include all Jython support in the Jar file, making it stand-alone. This enables us to run it on a system where Java is installed but Jython is not.

16.1   Calling Jython Code from Jython

From Jython, you can run Jython and Python code. When you do so, you may run Java code that is in a super-class or is used by the Jython code.

But, notice that, from Jython, you cannot call Python code that has been extended with C.

16.2   Calling Jython Code from Java

Must compile Jython/Python to Java with jythonc.

Must pay attention to method signatures. Define method signature in Jython in a doc string with @sig. Then look at the generated .java file.

Other things to be aware of:

  • Must set classpath to include jpywork.
  • Must write a Java compatible class. See above.

16.3   Another example -- Jython-2.2a/Demo/javaclasses

What this example shows:

  • How to write a class that can be compiled (with jythonc) and then called from Java.
  • How to write method signatures for Jython methods.
  • How to compile the the Jython code and the Java code.

For example, I compiled and ran the example in Jython-2.2a/Demo/javaclasses with the following:

$ rm -rf jpywork/
$ ../../jythonc --package pygraph Graph.py
$ javac -classpath .:../../jython.jar pygraph/PythonGraph.java
$ java -classpath .:../../jython.jar:jpywork pygraph.PythonGraph

For more information, see Jython-2.2a/Demo/javaclasses/readme.txt.



From:http://www.rexx.com/~dkuhlman/jython_course_01.html#another-example-jython-2-2a-demo-javaclasses

Blogged with Flock

1 comment:

Cell said...

I was getting trouble in embedding python within java until I read your blog. Your detailed instructions greatly do me a favor. Thanks you !

My photo
London, United Kingdom
twitter.com/zhengxin

Facebook & Twitter