Skip to content

Instantly share code, notes, and snippets.

@nrosner
Created March 4, 2017 02:25
Show Gist options
  • Save nrosner/70bed930684f467dddd5fc68cbf39e82 to your computer and use it in GitHub Desktop.
Save nrosner/70bed930684f467dddd5fc68cbf39e82 to your computer and use it in GitHub Desktop.
A Python script to count the number of classes and methods in a .jar file using javap.
#!/usr/bin/env python
import sys, os, re, zipfile, subprocess
# Rudimentary parsing of javap output
regex_type = r'[a-zA-Z0-9.<>, ?$[\]]+'
regex_class = r'(?:(public|private|protected) )?((?:(?:static|abstract|final) ?)*)(class|interface) (' + regex_type + ') (?:extends ((?:' + regex_type +'),?)+ )?(?:implements ((?:[a-zA-Z0-9\\.<>\\?\\$])+,?)+ )?{([^}]+)}'
regex_method = r'(?:(public|private|protected) )?((?:static|abstract|final) ?)*(?:(' + regex_type + ') )?([a-zA-Z]+)\\(([^\\)]*)\\)'
regex_field = r'(?:(public|private|protected) )?((?:(?:static|abstract|final) ?)*)(' + regex_type + ') ([a-zA-Z0-9]+)'
RE_TYPE = re.compile(regex_type)
RE_CLASS = re.compile(regex_class)
RE_METHOD = re.compile(regex_method)
RE_FIELD = re.compile(regex_field)
def classnamesfromjar(jarfilepath):
'''Return list of fully-qualified classnames.'''
with zipfile.ZipFile(jarfilepath, 'r') as zf:
for zi in zf.infolist():
fn = zi.filename
if fn.endswith('.class'):
dotted = fn.replace('/', '.')
assert dotted.endswith('.class')
yield dotted[:len(dotted)-len('.class')]
def runjavap(jarfilepath):
'''Run javap on this jar for all the classes in the jar. Return the output of the javap command.'''
classnames = classnamesfromjar(jarfilepath)
return runjavap_aux(classpath=jarfilepath, classnames=classnames)
def runjavap_aux(classpath, classnames):
'''Run javap on the given classpath for the given classnames. Return the output of the javap command.'''
cmdarglist = ['javap', '-classpath', classpath] + list(classnames)
p = subprocess.Popen(cmdarglist, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
tup_output = p.communicate()
stdout = tup_output[0]
stderr = tup_output[1]
return stdout
def countclassesandmethodsinjarfile(jarfilepath):
'''Return a tuple (nc, nm) with the number of classes and number of methods in the jarfile.'''
javap_output = runjavap(jarfilepath)
nc = len(RE_CLASS.findall(javap_output))
nm = len(RE_METHOD.findall(javap_output))
return nc, nm
if __name__ == '__main__':
for jarpathname in sys.argv[1:]:
nc, nm = countclassesandmethodsinjarfile(jarpathname)
print("%s\t%d\t%d" % (jarpathname, nc, nm))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment