I recently came across the term "Bytecode manipulation" (what made to look into this, by chance I saw bytecode provider while seeing the logs in an application which used Hibernate) . I also know (a bit) about Java Reflection API.
Are these two concepts similar? What are the difference between them? When to use which?
Reflection API allows you to access the information about the members (fields, methods, interfaces, e.t.c.) of classes which are already loaded to the JVM. This API doesn't allow to modify the behaviour of the class except for some basic stuff like calling private methods.
Some examples where Reflection API is applicable
- Dependency Injection framework can set the dependencies to the private fields of owner objects.
- You can use reflection to generate equals/hashCode/toString methods for your class without having to enumerate all the fields and modifying these methods when you add new fields or remove existing ones
- Serialize your class to JSON/XML/Yaml or any other format using Relfection Api again without having to enumerate over all the fields
ByteCode manipulation on the contrary allows you to make any changes you want either to some .class files on your disk or also to the classes which are already loaded to the JVM using Java Agent API
A few examples where bytecode manipulations are applicable:
- Proxies from Java standard library only supports proxying interfaces; bytecode manipulation allows you to add advices around class methods as well
- Mock frameworks for unit test allows to substitue the return values of private static methods - it is implemented using bytecode manipulations
- Profilers wrap each method with time recording code
Here's how it might look
private void foo() {
long start = System.currentTimeMillis(); // inserted by bytecode manipulation
Profiler.enterMethod("foo"); // inserted by bytecode manipulation
try { // inserted by bytecode manipulation
// original method code
} finally { // inserted by bytecode manipulation
Profiler.exitMethod("foo", System.currentTimeMillis() - start); // inserted by bytecode manipulation
} // inserted by bytecode manipulation
}