Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
34 lines
1.6 KiB
Python
34 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Dump the public API signatures of every exported class in the JDK's java.se-ish modules.
|
|
usage: dump_api.py <JAVA_HOME> <out-file>"""
|
|
import subprocess, sys, re, os
|
|
home, out = sys.argv[1], sys.argv[2]
|
|
env = {k:v for k,v in os.environ.items() if k!='JAVA_TOOL_OPTIONS'}
|
|
jimage = subprocess.run([f'{home}/bin/jimage','list',f'{home}/lib/modules'],capture_output=True,text=True,env=env).stdout
|
|
mods = {}
|
|
cur=None
|
|
for line in jimage.splitlines():
|
|
if line.startswith('Module: '): cur=line.split(': ')[1].strip(); mods[cur]=[]
|
|
elif cur and line.strip().endswith('.class'):
|
|
mods[cur].append(line.strip()[:-6])
|
|
WANT = re.compile(r'^(java|jdk\.(jfr|httpserver|incubator\.vector|management|net|jshell|jartool|jlink|jpackage|javadoc|compiler|jcmd|unsupported|security\.auth)|javafx)')
|
|
res=[]
|
|
for m,classes in sorted(mods.items()):
|
|
if not WANT.match(m): continue
|
|
names=[]
|
|
for c in classes:
|
|
if c=='module-info': continue
|
|
pk=c.rsplit('/',1)[0].replace('/','.') if '/' in c else ''
|
|
if re.search(r'(^|\.)(internal|impl)(\.|$)|^sun\.|^com\.sun\.(?!net\.httpserver|management|security\.auth|source)',pk): continue
|
|
names.append(c.replace('/','.'))
|
|
if not names: continue
|
|
# javap handles binary names with $ for nested
|
|
names=[n for n in names if not re.search(r'\$\d',n)]
|
|
txt=''
|
|
for i in range(0,len(names),200):
|
|
p=subprocess.run([f'{home}/bin/javap','--module',m,'-public']+names[i:i+200],capture_output=True,text=True,env=env)
|
|
txt+=p.stdout
|
|
res.append(f'##### MODULE {m}\n'+txt)
|
|
open(out,'w').write('\n'.join(res))
|
|
print(out, sum(len(r) for r in res)//1024,'KB')
|