Reputation: 7837
I'm writing a program which analyzes .class
files. I want to attach package and class name to my output.
My plan is to write a function which takes the package and class name as input and finds the corresponding .class
file (so the user doesn't have to enter that as well, and can't get it wrong), where 'find' should be read as 'give me some data I can use as arguments for BCEL's ClassParser
constructor' (either a filename, or a name of a zip file and a name within the zip file).
How do I go about that? Does java come with something which does that? I understand name resolution to be done in the context of a CLASSPATH
, so the user should probably supply one of those as well; that's fine.
Note: solutions should not execute any code from the .class
file. Just the bytes, ma'm ;-)
Upvotes: 0
Views: 207
Reputation: 7837
I want to thank the fine folks in irc://freenode.org/##java
for guiding me towards the following recipe:
// replace 'Throwable' with something else in production code :-)
JavaClass recipe() throws Throwable {
URLClassLoader loader = new URLClassLoader(new URL[] {
new URL("file:///usr/share/java/js.jar"),
});
String path = "org/mozilla/classfile/ByteCode.class";
InputStream resource = loader.getResourceAsStream(path);
String fake_filename = "<" + path + ">";
ClassParser classparser = new ClassParser(resource, fake_filename);
JavaClass java_class = classparser.parse();
// System.out.format("%s\n", jc);
return java_class;
}
One could de-hardcode the classpath and the value of path
by computing strings in the right format based on user input.
I'm going to use the answer I have accepted because it takes less work on my part, but I want to mention this answer because it is more generally applicable (i.e. with fewer dependencies).
Upvotes: 0
Reputation: 298469
Well, if you are using BCEL, everything is already there, see ClassPath
:
import java.io.IOException;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.util.ClassPath;
public class BcelTest {
public static void main(String[] args) throws IOException {
String classPath=System.getProperty("java.class.path");
// demonstrating with our own class path examplary for an arbitrary path String
ClassPath cp=new ClassPath(classPath);
ClassPath.ClassFile cf=cp.getClassFile(BcelTest.class.getName());
ClassParser p=new ClassParser(cf.getInputStream(), cf.getPath());
JavaClass jc = p.parse();
System.out.println(jc);
// or just using our own system path explicitly
cf=ClassPath.SYSTEM_CLASS_PATH.getClassFile("java.lang.Object");
p=new ClassParser(cf.getInputStream(), cf.getPath());
jc = p.parse();
System.out.println(jc);
}
}
Upvotes: 1
Reputation: 39451
If you already have the classfile, just replace every / in the class name with the directory separator for your system and append .class.
If you want to go from Java class name to bytecode class name, most classes are pretty simple. Prepend the package + '.' and replace '.' with '/'. For inner and nested classes, I'm not sure if there is a simple algorithm.
Upvotes: 0