#!/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 """ 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')