I'm searching for a way to get a list of method stubs of all classes within a jar file. I'm not sure where to start... May I use Reflection or Javassist or some other tools of which I've not heard yet!? At least it may be possible to unpack the jar, decompile the class files and scan with a line parser for methods, but I think that is the most dirtiest way ;-)
Any ideas?
Kind Regards
Building upon aioobe's answer, you can also use ASM's tree API (as opposed to its visitor API) to parse the contents of the class files contained within your JAR file. As well, you can read the files contained within the JAR file using the JarFile class. Here is an example of how this could be done:
The printMethodStubs
method accepts a JarFile
and proceeds to print out descriptions of all methods contained within all class files.
public void printMethodStubs(JarFile jarFile) throws Exception {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entryName.endsWith(".class")) {
ClassNode classNode = new ClassNode();
InputStream classFileInputStream = jarFile.getInputStream(entry);
try {
ClassReader classReader = new ClassReader(classFileInputStream);
classReader.accept(classNode, 0);
} finally {
classFileInputStream.close();
}
System.out.println(describeClass(classNode));
}
}
}
The describeClass
method accepts a ClassNode
object and proceeds to describe it and its associated methods:
public String describeClass(ClassNode classNode) {
StringBuilder classDescription = new StringBuilder();
Type classType = Type.getObjectType(classNode.name);
// The class signature (e.g. - "public class Foo")
if ((classNode.access & Opcodes.ACC_PUBLIC) != 0) {
classDescription.append("public ");
}
if ((classNode.access & Opcodes.ACC_PRIVATE) != 0) {
classDescription.append("private ");
}
if ((classNode.access & Opcodes.ACC_PROTECTED) != 0) {
classDescription.append("protected ");
}
if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) {
classDescription.append("abstract ");
}
if ((classNode.access & Opcodes.ACC_INTERFACE) != 0) {
classDescription.append("interface ");
} else {
classDescription.append("class ");
}
classDescription.append(classType.getClassName()).append("\n");
classDescription.append("{\n");
// The method signatures (e.g. - "public static void main(String[]) throws Exception")
@SuppressWarnings("unchecked")
List<MethodNode> methodNodes = classNode.methods;
for (MethodNode methodNode : methodNodes) {
String methodDescription = describeMethod(methodNode);
classDescription.append("\t").append(methodDescription).append("\n");
}
classDescription.append("}\n");
return classDescription.toString();
}
The describeMethod
method accepts a MethodNode
and returns a String describing the method's signature:
public String describeMethod(MethodNode methodNode) {
StringBuilder methodDescription = new StringBuilder();
Type returnType = Type.getReturnType(methodNode.desc);
Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
@SuppressWarnings("unchecked")
List<String> thrownInternalClassNames = methodNode.exceptions;
if ((methodNode.access & Opcodes.ACC_PUBLIC) != 0) {
methodDescription.append("public ");
}
if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) {
methodDescription.append("private ");
}
if ((methodNode.access & Opcodes.ACC_PROTECTED) != 0) {
methodDescription.append("protected ");
}
if ((methodNode.access & Opcodes.ACC_STATIC) != 0) {
methodDescription.append("static ");
}
if ((methodNode.access & Opcodes.ACC_ABSTRACT) != 0) {
methodDescription.append("abstract ");
}
if ((methodNode.access & Opcodes.ACC_SYNCHRONIZED) != 0) {
methodDescription.append("synchronized ");
}
methodDescription.append(returnType.getClassName());
methodDescription.append(" ");
methodDescription.append(methodNode.name);
methodDescription.append("(");
for (int i = 0; i < argumentTypes.length; i++) {
Type argumentType = argumentTypes[i];
if (i > 0) {
methodDescription.append(", ");
}
methodDescription.append(argumentType.getClassName());
}
methodDescription.append(")");
if (!thrownInternalClassNames.isEmpty()) {
methodDescription.append(" throws ");
int i = 0;
for (String thrownInternalClassName : thrownInternalClassNames) {
if (i > 0) {
methodDescription.append(", ");
}
methodDescription.append(Type.getObjectType(thrownInternalClassName).getClassName());
i++;
}
}
return methodDescription.toString();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With