Reputation: 2795
If I have a Class instance at runtime, can I get its byte[] representation? The bytes I'm interested in would be in the Class file format, such that they'd be valid input to [ClassLoader.defineClass][3].
[3]: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html#defineClass(java.lang.String, byte[], int, int)
EDIT: I've accepted a getResourceAsStream answer, because it's very simple and will work most of the time. ClassFileTransformer seems like a more robust solution because it doesn't require that classes be loaded from .class files; it would handle network-loaded classes for example. There's a few hoops to jump through with that approach, but I'll keep in in mind. Thanks all!
Upvotes: 31
Views: 19218
Reputation:
Here's a bit of help,
use
final Class<T> clazz = ...
final byte[] buffer = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/').concat(".class"));
to get the compiled byte code of the class.
And use
class SimpleClassLoader extends ClassLoader {
public Clazz<?> loadFromBuffer(final byte[] buffer) {
return defineClass(buffer, 0, buffer.length);
}
public Object newObjectFromBuffer(final byte[] buffer) {
return loadFromBuffer(buffer).newInstance();
}
}
to instantiate an Object
or to load the Class
back from the buffer.
Upvotes: 0
Reputation: 70201
You can usually just load the class as a resource from the Classloader.
Class c = ...
String className = c.getName();
String classAsPath = className.replace('.', '/') + ".class";
InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath);
I would probably recommend using something from Apache commons-io to read the InputStream into a byte[]
, but IOUtils.toByteArray()
should do the trick. Writing that code is really easy to get wrong and/or make slow.
Upvotes: 30
Reputation: 24791
You can try java instrumentation! In particular ClassFileTransformer maybe of interest to you!!
You simply override the transform method (from ClassFileTransformer), and your transform method will be called before each class is loaded. So then you cna do whatever class bytes.
Upvotes: 2
Reputation: 147154
In general you can't go back like that. However, for some class loaders you may be able to get the resource file be taking the fully qualified class name, replacing .
with /
and appending .class
(so mypackage.MyClass
becomes mypackage/MyClass.class
(remember, may be case sensitive)).
Upvotes: 2