12

Related to: Is there a way to obtain the bytecode for a class at runtime?

I'm adding durability to Clojure, and I'm finally at the point where I'm ready to add functions. In Clojure, functions are byte compiled into classes with invoke methods (among others). In this way, functions are first class. To make these durable, I need to serialize and deserialize these classes. How do I get the bytecode for the class without having access to the .class file?

Please correct me if I'm mistaken, but using an agent requires spawning a separate VM with the agent connecting to the first VM. I need to do it from the same VM.

It's not enough to use Serializable to set and get the Class object. Upon deserializing, I need to load the class, and upon subsequent VM instances, there may be a class name collision. I need to modify the bytecode to rename the class to something unique at deserialization/class-load time.

1
  • I'm by no means an expert on the topic, but it might be worth trying to persist the function definitions rather than the underlying bytecode. you can then just recompile the functions to bytecode when you load them back in. Commented Nov 9, 2010 at 20:27

3 Answers 3

5

You could write your own ClassLoader and hack up a scheme which records the bytecode as classes are loaded.

You would need to override findClass to find the class file yourself, load it into memory, save the data somewhere (for later serialization), then call defineClass to define that class in the JVM.

Sign up to request clarification or add additional context in comments.

3 Comments

p.s. I think agents run in the same VM as the main program, so they may work for you.
Javassist already implements this scheme and offers a somewhat convenient access to the bytecode in question. BCEL might also do something similar.
Minimal implementation is pretty trivial: gist.github.com/Felk/ed4375d27c755e21d0e6893847286d93 (I know this post is 7 years old)
3

Unless you are running code via a tricky classloader, you should be able to do something like this:

Class<?> clazz = ....
String className = clazz.getCanonicalName();  // e.g. "foo.Bar"
String resourceName = ... // map className to a resource name; e.g. "/foo/Bar.class" 
InputStream is = clazz.getClassLoader().getResourceAsStream(resourceName);

This gives you a handle on the contents of the ".class" file ... if it can be found.

Caveats. Some classloaders might:

  • not let to open the ".class" resources at all,
  • give you an encrypted bytecode stream, or
  • give you bytecodes that are nor exactly what is being run, due to some on-the-fly transformation performed by the classloader.

If this approach doesn't work, you are pretty much out of options because the JVM does not provide a way to access the actual bytecodes that were loaded.

3 Comments

Alas, this only works if the .class is written to disk as a resource in the first place. Clojure does not do this.
It also has problems when the class is defined inside another. Eg.: class Foo { class Bar {} } should become "/Foo$Bar.class"
clazz.getResourceAsStream('/'+clazz.getName().replace('.', '/')+".class") works with inner classes and even with bootstrap classes having a null ClassLoader.
1

You can also use the Java Instrumentation API for this. You get access to the bytes of the classfile before defineClass is invoked. You can change them too!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.