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