paul@135 | 1 | <?xml version="1.0" encoding="iso-8859-1"?> |
paul@135 | 2 | <html xmlns="http://www.w3.org/1999/xhtml"> |
paul@135 | 3 | <head> |
paul@139 | 4 | <title>javaclass/ClassFile</title> |
paul@135 | 5 | <meta name="generator" content="amaya 8.1a, see http://www.w3.org/Amaya/" /> |
paul@135 | 6 | <link xmlns:xlink="http://www.w3.org/1999/xlink" href="styles.css" |
paul@135 | 7 | rel="stylesheet" type="text/css" /> |
paul@135 | 8 | </head> |
paul@135 | 9 | |
paul@135 | 10 | <body> |
paul@139 | 11 | <h1>javaclass</h1> |
paul@139 | 12 | |
paul@139 | 13 | <p>The javaclass collection of packages and utilities (also known as |
paul@139 | 14 | ClassFile) provides a means of importing Java classes and packages directly |
paul@139 | 15 | into Python, without the need for a Java virtual machine, so that the classes |
paul@139 | 16 | may be instantiated, accessed, run and manipulated just like Python classes, |
paul@139 | 17 | and that the resulting objects and methods can be accessed and manipulated |
paul@140 | 18 | just like Python objects and methods. It should be possible to run compiled |
paul@140 | 19 | Java programs with the Python interpreter and not notice that it isn't the |
paul@140 | 20 | Java virtual machine being used - given sufficient library support for the |
paul@140 | 21 | program concerned, of course.</p> |
paul@135 | 22 | |
paul@139 | 23 | <h2>Quick Examples</h2> |
paul@139 | 24 | |
paul@139 | 25 | <p>It can be quicker to see what this is about by seeing some examples.</p> |
paul@135 | 26 | |
paul@139 | 27 | <h3>The Not Very Convincing Example</h3> |
paul@139 | 28 | |
paul@139 | 29 | <p>You can run Java classes by finding one with a main method and executing |
paul@139 | 30 | it. Here's a comparison of a freshly prepared Java class being run in Python |
paul@149 | 31 | and in a Java virtual machine respectively:</p> |
paul@152 | 32 | <pre class="Prompt">cd tests/</pre> |
paul@152 | 33 | <pre class="Prompt">javac Value.java</pre> |
paul@152 | 34 | <pre class="PromptRequest">runclass.py Value</pre> |
paul@152 | 35 | <pre class="PromptResponse">v.getValue() correct: 123 |
paul@152 | 36 | v.getValue() correct: 456 |
paul@152 | 37 | v.isPositive() correct: 1 |
paul@152 | 38 | v.isPositive() correct: 0 |
paul@152 | 39 | v.compare(-790) correct: -1 |
paul@152 | 40 | v.compare(-788) correct: 1 |
paul@152 | 41 | v.compare(-789) correct: 0 |
paul@152 | 42 | v.getValue() == v2.getValue() correct: 0 |
paul@152 | 43 | v2.add(-123) correct: 0 |
paul@152 | 44 | v2.getValue() correct: 255</pre> |
paul@152 | 45 | <pre class="PromptRequest">java Value</pre> |
paul@152 | 46 | <pre class="PromptResponse">v.getValue() correct: 123 |
paul@152 | 47 | v.getValue() correct: 456 |
paul@152 | 48 | v.isPositive() correct: true |
paul@152 | 49 | v.isPositive() correct: false |
paul@152 | 50 | v.compare(-790) correct: -1 |
paul@152 | 51 | v.compare(-788) correct: 1 |
paul@152 | 52 | v.compare(-789) correct: 0 |
paul@152 | 53 | v.getValue() == v2.getValue() correct: false |
paul@152 | 54 | v2.add(-123) correct: 0 |
paul@152 | 55 | v2.getValue() correct: 255</pre> |
paul@135 | 56 | |
paul@139 | 57 | <h3>The Slightly More Credible Example</h3> |
paul@139 | 58 | |
paul@139 | 59 | <p>It can be more interesting to get into Python's interactive mode and then |
paul@139 | 60 | start playing around with Java classes:</p> |
paul@152 | 61 | <pre class="PromptResponse">Python 2.2.2 (#2, Jan 21 2005, 16:16:57) |
paul@152 | 62 | [GCC 2.96 20000731 (Red Hat Linux 7.3 2.96-112)] on linux2 |
paul@152 | 63 | Type "help", "copyright", "credits" or "license" for more information.</pre> |
paul@152 | 64 | <pre class="PythonPrompt">import javaclass.classhook</pre> |
paul@152 | 65 | <pre class="PythonPrompt">from __this__ import Value</pre> |
paul@152 | 66 | <pre class="PythonPrompt">dir()</pre> |
paul@152 | 67 | <pre class="PromptResponse">['Value', '__builtins__', '__doc__', '__name__', |
paul@152 | 68 | 'javaclass']</pre> |
paul@152 | 69 | <pre class="PythonPrompt">dir(Value)</pre> |
paul@152 | 70 | <pre class="PromptResponse">['__class__', '__delattr__', '__dict__', '__doc__', |
paul@139 | 71 | '__getattribute__', '__hash__', '__init__', '__init______I_', '__module__', |
paul@139 | 72 | '__new__', '__reduce__', '__repr__', '__setattr__', '__str__', '__weakref__', |
paul@139 | 73 | 'add', 'add____I_', 'compare', 'compare____I_', 'getClass', 'getClass___', |
paul@139 | 74 | 'getValue', 'getValue___', 'isPositive', 'isPositive___', 'main', |
paul@139 | 75 | 'main___java__lang__String_array_', 'newValue', 'newValue___', 'setValue', |
paul@152 | 76 | 'setValue____I_']</pre> |
paul@152 | 77 | <pre class="PythonPrompt">v = Value(20050121)</pre> |
paul@152 | 78 | <pre class="PythonPrompt">v.getValue()</pre> |
paul@152 | 79 | <pre class="PromptResponse">20050121</pre> |
paul@152 | 80 | <pre class="PythonPrompt">v.setValue(20050401)</pre> |
paul@152 | 81 | <pre class="PythonPrompt">v.getValue()</pre> |
paul@152 | 82 | <pre class="PromptResponse">20050401</pre> |
paul@139 | 83 | |
paul@152 | 84 | <h2>Copyright and Licence</h2> |
paul@139 | 85 | |
paul@152 | 86 | <p>The javaclass software is distributed under the terms of the GNU Lesser |
paul@152 | 87 | General Public Licence (LGPL). See the file <code>COPYING.txt</code> in the |
paul@152 | 88 | <code>docs</code> directory within the source code distribution.</p> |
paul@139 | 89 | |
paul@140 | 90 | <h2>Getting Started</h2> |
paul@140 | 91 | |
paul@140 | 92 | <p>See the <code>README.txt</code> file in the distribution directory.</p> |
paul@140 | 93 | |
paul@135 | 94 | <h2>Motivation</h2> |
paul@135 | 95 | |
paul@135 | 96 | <p>Pick one of the following:</p> |
paul@135 | 97 | <ul> |
paul@135 | 98 | <li>The need/desire to access Java libraries from Python without firing up |
paul@140 | 99 | Java virtual machines or switching to Jython (and thereby losing |
paul@140 | 100 | convenient access to various CPython libraries).</li> |
paul@140 | 101 | <li>Mixing languages available for the Java runtime with Python.</li> |
paul@135 | 102 | <li>Static typing for the Python environment, albeit achieved by writing |
paul@135 | 103 | Java or other appropriate languages.</li> |
paul@135 | 104 | <li>Having an open source environment from top to bottom to run Java |
paul@135 | 105 | bytecode on.</li> |
paul@135 | 106 | <li>Experimentation around import hooks, bytecode generation; observation |
paul@135 | 107 | of different runtime and type systems interacting.</li> |
paul@140 | 108 | <li>Making Python libraries available to Java programs - Tkinter for Java, |
paul@140 | 109 | anyone?!</li> |
paul@139 | 110 | </ul> |
paul@139 | 111 | |
paul@139 | 112 | <h2>Limitations</h2> |
paul@139 | 113 | |
paul@139 | 114 | <p>It isn't all great, however. Here are some reasons why this might not do |
paul@139 | 115 | what you want it to:</p> |
paul@139 | 116 | <ul> |
paul@139 | 117 | <li>It runs on the Python runtime which does not have the security, |
paul@139 | 118 | threading and just-in-time compiler features that people enjoy about Java |
paul@139 | 119 | runtimes, so if what you like to do is to run one big servlet container |
paul@139 | 120 | with lots of classes and threads from different people floating around, |
paul@139 | 121 | this isn't going to protect them from doing all sorts of things to each |
paul@139 | 122 | other and to your system. However, you may take the unfashionable view |
paul@139 | 123 | that the operating system is supposed to do that kind of thing.</li> |
paul@139 | 124 | <li>It works by generating Python bytecode from the Java bytecode in class |
paul@139 | 125 | files (and .jar archives). Generally, anyone who is anyone in the Python |
paul@139 | 126 | pantheon has largely recommended against doing anything with the |
paul@139 | 127 | bytecode, despite noble efforts to make exciting things happen by |
paul@140 | 128 | transforming it, optimising it, and so on. (Instead, there's been more |
paul@140 | 129 | emphasis on lots of runtime baggage for things which could be done by |
paul@140 | 130 | analysis of the code with modified bytecode being produced as a result, |
paul@149 | 131 | and let's not get started on some of the syntax enhancements!) |
paul@140 | 132 | Consequently, stability might be an issue for some configurations, |
paul@140 | 133 | especially since CPython doesn't fail particularly graciously with badly |
paul@140 | 134 | behaved bytecode.</li> |
paul@140 | 135 | <li>Some of the translation from Java to Python bytecode takes a few |
paul@140 | 136 | liberties. For example, Java exceptions are handled in ways reminiscent |
paul@140 | 137 | of a 1980s microcomputer assembly language, whereas Python bytecode has |
paul@140 | 138 | higher level constructs for exceptions; this translation can probably be |
paul@140 | 139 | done incorrectly, triggering some kind of bytecode misbehaviour, and we |
paul@140 | 140 | all know what happens then.</li> |
paul@140 | 141 | <li>At the Python level, not all things seem totally right. For example, |
paul@140 | 142 | Java bytecode instructions are used to instantiate and then initialise |
paul@140 | 143 | exceptions just like other objects, and while Python can support this |
paul@140 | 144 | with new-style objects, Python won't let you use new-style objects as |
paul@140 | 145 | exceptions. Consequently, when Java exceptions appear in Python programs, |
paul@140 | 146 | they will be wrapped in old-style exceptions and have to be handled |
paul@140 | 147 | specially.</li> |
paul@140 | 148 | <li>In order to support method dispatch properly, special names are used |
paul@140 | 149 | for the translated methods which include the type information found in |
paul@140 | 150 | the bytecode; things like <code>main___java__lang__String_array_</code> |
paul@140 | 151 | and <code>setValue____I_</code> appear when you look inside classes and |
paul@140 | 152 | objects. When implementing libraries in Python for Java programs, such |
paul@140 | 153 | method naming conventions have to be used because the original code is |
paul@140 | 154 | very specific about which method is being invoked, and for specialised |
paul@140 | 155 | versions of <code>__init__</code> it becomes necessary to do a |
paul@140 | 156 | <code>setattr</code> to add such methods into classes because of various |
paul@140 | 157 | "name mangling" measures in the Python compilation process. Now, many |
paul@140 | 158 | people might start advocating decorators at this point, but not everyone |
paul@140 | 159 | is running the very latest stuff from python.org, and decorators won't |
paul@140 | 160 | help you target a specific specialised method anyway.</li> |
paul@145 | 161 | <li>Special dispatcher methods are often generated for the benefit of |
paul@145 | 162 | Python access to Java classes, even though such methods are not strictly |
paul@145 | 163 | necessary for the Java classes to work amongst themselves. Such methods |
paul@145 | 164 | are only generated when many methods of the same name reside in a given |
paul@145 | 165 | class, since where Java distinguishes between them on the basis of the |
paul@145 | 166 | signatures, Python permits only one method of a given name and needs |
paul@145 | 167 | additional logic to dispatch to the actual method implementations on the |
paul@145 | 168 | basis of the types of the incoming values. The implementation of the |
paul@145 | 169 | dispatcher method is naive and does not try to order the type checks and |
paul@145 | 170 | dispatches according to the specificity of the parameter types; thus, a |
paul@145 | 171 | more reliable but more verbose way of ensuring that the correct method in |
paul@145 | 172 | such cases is called from a Python program may be to use the special long |
paul@145 | 173 | method name (eg. <code>setValue____I_</code>).</li> |
paul@140 | 174 | <li>Imported and translated bytecode is not written out or cached. This |
paul@140 | 175 | means that a fair amount of work happens every time you need to import |
paul@140 | 176 | Java classes, although the generation of .pyc files could be introduced |
paul@140 | 177 | provided that it captured the slightly different import semantics of |
paul@140 | 178 | Java; for example, you can import classes belonging to a package from |
paul@140 | 179 | several places on the PYTHONPATH, and this is something that generally |
paul@140 | 180 | isn't allowed/supported with the classic Python module import |
paul@140 | 181 | mechanisms.</li> |
paul@149 | 182 | <li>Most Java programs need standard Java library (also known as the Java |
paul@149 | 183 | API) classes; indeed, with <code>java.lang.String</code> and seemingly |
paul@149 | 184 | <code>java.lang.StringBuffer</code> required just for the usage of |
paul@149 | 185 | strings, and with the classic <code>main</code> method having |
paul@149 | 186 | <code>String[]</code> in its signature, some kind of library |
paul@149 | 187 | implementation is obviously necessary. Whilst importing everything from |
paul@149 | 188 | the .jar files bundled with Sun's JRE might be tempting, there may be a |
paul@149 | 189 | certain amount of native calling going on in secret which would defeat |
paul@149 | 190 | this approach, and anyone seriously interested in running Java code in |
paul@149 | 191 | Python should really want to steer clear of such proprietary dependencies |
paul@149 | 192 | anyway. It could be possible to wrap and make use of GNU Classpath or |
paul@149 | 193 | some other open source Java API implementation, but the cleanest (but not |
paul@149 | 194 | necessarily the least time-consuming) approach is surely to implement the |
paul@149 | 195 | standard API classes in Python, and a package called <code>java</code> is |
paul@149 | 196 | included which contains some fairly quick and dirty implementations to |
paul@149 | 197 | get things working.</li> |
paul@140 | 198 | </ul> |
paul@140 | 199 | |
paul@140 | 200 | <h2>Suggestions for Python Improvements</h2> |
paul@140 | 201 | <ul> |
paul@140 | 202 | <li>Make the bytecode interpreter more robust when encountering badly |
paul@140 | 203 | behaved bytecode, consider bytecode verification and other exciting |
paul@140 | 204 | features.</li> |
paul@140 | 205 | <li>Allow new-style objects as exceptions. Actually, just do something |
paul@140 | 206 | about the whole old-style vs. new-style class thing!</li> |
paul@140 | 207 | <li>Allow possible optimisation for things like statically predetermined |
paul@140 | 208 | method calls. The debate about static typing intersects slightly with the |
paul@140 | 209 | need to define methods with parameters of particular types, but |
paul@140 | 210 | supporting Java-style method "coexistence" (or multimethods, or whatever |
paul@140 | 211 | the proper name is) would presumably involve doing lots of things to the |
paul@140 | 212 | language that were once thought to be highly un-Pythonic. Besides, the |
paul@140 | 213 | need to interoperate with statically typed languages shouldn't dictate |
paul@140 | 214 | the design of Python, especially if better type systems could be adopted |
paul@140 | 215 | instead, leaving the static typing glue for strictly special |
paul@140 | 216 | occasions.</li> |
paul@140 | 217 | <li>Not that threaded Java programs have been run on Python yet, but with |
paul@140 | 218 | Python's current threading architecture I'd expect some |
paul@140 | 219 | disappointment.</li> |
paul@135 | 220 | </ul> |
paul@135 | 221 | </body> |
paul@135 | 222 | </html> |