javaclass
The javaclass collection of packages and utilities (also known as
ClassFile) provides a means of importing Java classes and packages directly
into Python, without the need for a Java virtual machine, so that the classes
may be instantiated, accessed, run and manipulated just like Python classes,
and that the resulting objects and methods can be accessed and manipulated
just like Python objects and methods. It should be possible to run compiled
Java programs with the Python interpreter and not notice that it isn't the
Java virtual machine being used - given sufficient library support for the
program concerned, of course.
Quick Examples
It can be quicker to see what this is about by seeing some examples.
The Not Very Convincing Example
You can run Java classes by finding one with a main method and executing
it. Here's a comparison of a freshly prepared Java class being run in Python
and in a Java virtual machine:
cd tests/
javac Value.java
runclass.py Value
v.getValue() correct: 123
v.getValue() correct: 456
v.isPositive() correct: 1
v.isPositive() correct: 0
v.compare(-790) correct: -1
v.compare(-788) correct: 1
v.compare(-789) correct: 0
v.getValue() == v2.getValue() correct: 0
v2.add(-123) correct: 0
v2.getValue() correct: 255
java Value
v.getValue() correct: 123
v.getValue() correct: 456
v.isPositive() correct: true
v.isPositive() correct: false
v.compare(-790) correct: -1
v.compare(-788) correct: 1
v.compare(-789) correct: 0
v.getValue() == v2.getValue() correct: false
v2.add(-123) correct: 0
v2.getValue() correct: 255
The Slightly More Credible Example
It can be more interesting to get into Python's interactive mode and then
start playing around with Java classes:
Python 2.2.2 (#2, Jan 21 2005, 16:16:57)
[GCC 2.96 20000731 (Red Hat Linux 7.3 2.96-112)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import javaclass.classhook
from __this__ import Value
dir()
['Value', '__builtins__', '__doc__', '__name__',
'javaclass']
dir(Value)
['__class__', '__delattr__', '__dict__', '__doc__',
'__getattribute__', '__hash__', '__init__', '__init______I_', '__module__',
'__new__', '__reduce__', '__repr__', '__setattr__', '__str__', '__weakref__',
'add', 'add____I_', 'compare', 'compare____I_', 'getClass', 'getClass___',
'getValue', 'getValue___', 'isPositive', 'isPositive___', 'main',
'main___java__lang__String_array_', 'newValue', 'newValue___', 'setValue',
'setValue____I_']
v = Value(20050121)
v.getValue()
20050121
v.setValue(20050401)
v.getValue()
20050401
Getting Started
See the README.txt
file in the distribution directory.
Motivation
Pick one of the following:
- The need/desire to access Java libraries from Python without firing up
Java virtual machines or switching to Jython (and thereby losing
convenient access to various CPython libraries).
- Mixing languages available for the Java runtime with Python.
- Static typing for the Python environment, albeit achieved by writing
Java or other appropriate languages.
- Having an open source environment from top to bottom to run Java
bytecode on.
- Experimentation around import hooks, bytecode generation; observation
of different runtime and type systems interacting.
- Making Python libraries available to Java programs - Tkinter for Java,
anyone?!
Limitations
It isn't all great, however. Here are some reasons why this might not do
what you want it to:
- It runs on the Python runtime which does not have the security,
threading and just-in-time compiler features that people enjoy about Java
runtimes, so if what you like to do is to run one big servlet container
with lots of classes and threads from different people floating around,
this isn't going to protect them from doing all sorts of things to each
other and to your system. However, you may take the unfashionable view
that the operating system is supposed to do that kind of thing.
- It works by generating Python bytecode from the Java bytecode in class
files (and .jar archives). Generally, anyone who is anyone in the Python
pantheon has largely recommended against doing anything with the
bytecode, despite noble efforts to make exciting things happen by
transforming it, optimising it, and so on. (Instead, there's been more
emphasis on lots of runtime baggage for things which could be done by
analysis of the code with modified bytecode being produced as a result,
and let's not get started on some of the syntactical enhancements.)
Consequently, stability might be an issue for some configurations,
especially since CPython doesn't fail particularly graciously with badly
behaved bytecode.
- Some of the translation from Java to Python bytecode takes a few
liberties. For example, Java exceptions are handled in ways reminiscent
of a 1980s microcomputer assembly language, whereas Python bytecode has
higher level constructs for exceptions; this translation can probably be
done incorrectly, triggering some kind of bytecode misbehaviour, and we
all know what happens then.
- At the Python level, not all things seem totally right. For example,
Java bytecode instructions are used to instantiate and then initialise
exceptions just like other objects, and while Python can support this
with new-style objects, Python won't let you use new-style objects as
exceptions. Consequently, when Java exceptions appear in Python programs,
they will be wrapped in old-style exceptions and have to be handled
specially.
- In order to support method dispatch properly, special names are used
for the translated methods which include the type information found in
the bytecode; things like
main___java__lang__String_array_
and setValue____I_
appear when you look inside classes and
objects. When implementing libraries in Python for Java programs, such
method naming conventions have to be used because the original code is
very specific about which method is being invoked, and for specialised
versions of __init__
it becomes necessary to do a
setattr
to add such methods into classes because of various
"name mangling" measures in the Python compilation process. Now, many
people might start advocating decorators at this point, but not everyone
is running the very latest stuff from python.org, and decorators won't
help you target a specific specialised method anyway.
- Imported and translated bytecode is not written out or cached. This
means that a fair amount of work happens every time you need to import
Java classes, although the generation of .pyc files could be introduced
provided that it captured the slightly different import semantics of
Java; for example, you can import classes belonging to a package from
several places on the PYTHONPATH, and this is something that generally
isn't allowed/supported with the classic Python module import
mechanisms.
Suggestions for Python Improvements
- Make the bytecode interpreter more robust when encountering badly
behaved bytecode, consider bytecode verification and other exciting
features.
- Allow new-style objects as exceptions. Actually, just do something
about the whole old-style vs. new-style class thing!
- Allow possible optimisation for things like statically predetermined
method calls. The debate about static typing intersects slightly with the
need to define methods with parameters of particular types, but
supporting Java-style method "coexistence" (or multimethods, or whatever
the proper name is) would presumably involve doing lots of things to the
language that were once thought to be highly un-Pythonic. Besides, the
need to interoperate with statically typed languages shouldn't dictate
the design of Python, especially if better type systems could be adopted
instead, leaving the static typing glue for strictly special
occasions.
- Not that threaded Java programs have been run on Python yet, but with
Python's current threading architecture I'd expect some
disappointment.