|
| 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