Skip to content

Commit dc4064f

Browse files
committed
very very fast implementation of a converter Java -> Python class
1 parent 6f32a6f commit dc4064f

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

distribute.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ function run_distribute() {
525525
try cp -a $SRC_PATH/default.properties .
526526
try cp -a $SRC_PATH/local.properties .
527527
try cp -a $SRC_PATH/build.py .
528+
try cp -a $SRC_PATH/java2python.py .
528529
try cp -a $SRC_PATH/buildlib .
529530
try cp -a $SRC_PATH/src .
530531
try cp -a $SRC_PATH/templates .

src/java2python.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import sys
2+
import subprocess
3+
4+
def parse_signature(java, jni):
5+
if not jni.startswith(' Signature: '):
6+
print 'invalid signature'
7+
return
8+
jni = jni[13:]
9+
javas = java.split()
10+
11+
if javas[0] in ('public', 'private', 'protected'):
12+
javas.pop(0)
13+
14+
is_static = False
15+
if javas[0] == 'static':
16+
javas.pop(0)
17+
is_static = True
18+
19+
if jni[0] == '(':
20+
if javas[0][0] == '{':
21+
return
22+
if javas[0] in ('public', 'private', 'protected'):
23+
javas.pop(0)
24+
# method
25+
if '(' in javas[0]:
26+
# constructor
27+
return ('constructor', '', jni)
28+
else:
29+
javas.pop(0)
30+
name = javas[0].split('(')[0]
31+
if is_static:
32+
return ('staticmethod', name, jni)
33+
return ('method', name, jni)
34+
else:
35+
# field
36+
if javas[0] in ('public', 'private', 'protected'):
37+
javas.pop(0)
38+
name = javas[1].split(';')[0]
39+
if is_static:
40+
return ('staticfield', name, jni)
41+
return ('field', name, jni)
42+
43+
def parse(filename):
44+
cmd = subprocess.Popen(['javap', '-s', filename], stdout=subprocess.PIPE)
45+
stdout = cmd.communicate()[0]
46+
lines = stdout.splitlines()[1:]
47+
48+
line = lines.pop(0)
49+
if not line.startswith('public class') and not line.startswith('class'):
50+
print '-> not a public class, exit.'
51+
return []
52+
53+
javaclass = line[13:].split('{')[0].split(' ')[0]
54+
pythonclass = javaclass.rsplit('.')[-1]
55+
56+
members = []
57+
while len(lines) > 2:
58+
javasignature = lines.pop(0)
59+
jnisignature = lines.pop(0)
60+
member = parse_signature(javasignature, jnisignature)
61+
if member is None:
62+
continue
63+
members.append(member)
64+
65+
return (javaclass, pythonclass, members)
66+
67+
68+
def generate(defs):
69+
javaclass, pythonclass, members = defs
70+
output = '''
71+
from java import MetaJavaClass, JavaClass, JavaMethod, \\
72+
JavaStaticMethod, JavaField, JavaStaticField
73+
74+
class {0!r}(JavaClass):
75+
__metaclass__ = MetaJavaClass
76+
__javaclass__ = '{1!r}'
77+
78+
'''.format(pythonclass, javaclass)
79+
80+
pyclasses = {
81+
'method': 'JavaMethod',
82+
'staticmethod': 'JavaStaticMethod',
83+
'field': 'JavaField',
84+
'staticfield': 'JavaStaticField' }
85+
86+
for member in members:
87+
tp, name, sig = member
88+
if tp == 'constructor':
89+
output += ' __javaconstructor__ = {0!r}\n'.format(sig)
90+
continue
91+
cls = pyclasses[tp]
92+
output += ' {0} = {1}({2!r})\n'.format(name, cls, sig)
93+
94+
return output
95+
96+
97+
98+
if __name__ == '__main__':
99+
filename = sys.argv[1]
100+
if filename.endswith('.class'):
101+
filename = filename[:-6]
102+
print generate(parse(filename))

0 commit comments

Comments
 (0)