Transcript JavAssist
JavAssist
X.java
compile
X.class
load
Class
Loader
My
Loader
X
JavAssist enables preload byte code modification
What is Reflection?
If a program can inspect itself
while running, it’s said that the runtime
system is reflective with respect to that
program.
Levels of Reflection
• Introspection.
– No alteration, read only.
• Behavioral Reflection.
– Limited Alteration possible, such as method invocation.
– In general : behavior of operations is changeable.
• Structural Reflection.
– The ability to change data structures used by the
runtime system, such as Class for example.
Java, AspectJ, and JavAssist
• Java provides Introspection:
– getName.
• AspectJ provides Behavioral Reflection:
– Aspects + Point cuts are used.
– Compile time Weaving process integrates behavioral
changes to precompiled base code.
• Javassist provides Structural Reflection:
– Javassist API is in Java.
– Customized runtime loader changes preloaded byte
code.
How is Javassist implemented?
CtClass c = new CtClass(“X.class”);
//There’s nothing like Class X in the JVM so far!
c.notFinal();
c.addField(…)
c.addMethod(…)
//c contains the altered byte code of X.
c.load();
//Altered X is finally loaded into the JVM.
c
X’
My
Loader
X.class
Design Goals of Javassist
1. Source Level Abstraction.
No knowledge of byte code is needed.
API is purely in Java.
2. Efficient Structural Reflection.
Reduce runtime overheads due to class reconstruction.
3. Safe Structural Reflection.
Protect programmers from defected byte code composition.
Pursuing Javassist Design Goals.
1. Source Level Abstraction.
Class rename.
2. Efficient Structural Reflection.
Runtime compilation with addMethod.
3. Safe Structural Reflection.
Class member removal.
The Javassist API
CtClass{
}
Class{
CtFields
Fields
CtMethods
Constructors
CtMethods
Methods
}
•Introspection
•Alteration.
•Adding a new Member.
•Altering a Method Body.
•Javassist Class Loader.
CtClass Introspection
CtField & CtMethod Introspection
Alteration
Example: addMethod
public class Xvector extends java.util.vector{
public void add(X e){
super.addElement(e);
}
}
CtMethod m = // method add() in XVector
CtClass c = // class StringVector
Classmap = new ClassMap();
map.put(“X” , ”java.lang.String”);
c.addMethod(m, “addString”, map);
Public void addString(java.lang.String e){
super.addElement(e);
}
Example: setBody
M( … ){
…
Xclass xclass = new Xclass(3,4);
…
}
CtMethod m = // method which body is to be changed
CodeConverter conv = new CodeConverter();
Conv.replaceNew(Xclass, Yclass, “create” );
m.instrument(conv);
M( … ){
…
Yclass.create(3,4);
…
}
Must be Static
Reflective Class Loader
•JavAssist default loader.
•User defined loader.
•Web Server.
•Off line.
Examples: Binary Code
Adaptation.
class X implements Writable{
public void write(PrintableStream s){..}
}
class X implements Printable{
public void (PrintableStream s){..}
public void print(){write(System.out);}
}
Examples: Binary Code Adaptation.
class Exemplar implements Printable {
public void write(PrintStream s) { /* dummy */ }
public void print() { write(System.out); }
}
class Adaptor { // THE JOB IS DONE HERE
public void adapt(CtClass c) {
CtMethod printM = /* method print() in
Exemplar */;
CtClass[] interfaces =
c.getInterfaces();
for (int i = 0; i < interfaces.length;
++i)
if
(interfaces[i].getName().equals("Writable")) {
interfaces[i] =
CtClass.forName("Printable");
c.setInterfaces(interfaces);
c.addMethod(printM, new
ClassMap());
Behavioral Reflection.
public class MyMetaObject extends MetaObject {
public Object trapMethodCall(String
methodName, Object[] args) {
/* called if a method call is intercepted. */ }
public Object trapFieldRead(String
fieldName) {
/* called if the value of a field is read. */ }
public void trapFieldWrite(String
fieldName, Object value) {
/* called if a field is set. */ }
}
Behavioral Reflection.
public class C{
public int f;
public int m(int x){ return x+f;}
}
public class C implements MetaLevel {
public int m(int x) { /* notify a MetaObject. */ }
public int f;
private MetaObject _MetaObject = new MyMetaObjec
public MetaObject _getMetaObject() { return _Met
public int orig_m(int x) { return x + f; }
public static int read_f(Object target) {/*notify
public static void write_f(Object target, int v
/*notify a MetaObject. */ }
}
Behavioral Reflection.
class Exemplar {
private MetaObject _MetaObject;
public Object trap(Object[] args, String
methodName) {
return
_MetaObject.trapMethodcall(methodName, args);
}
public static Object trapRead(Object[] args,
String name) {
Metalevel target = (Metalevel)args[0];
return
target._getMetaObject().trapFieldRead(name);
}
public static Object trapWrite(Object[] args,
String name) {
Metalevel target = (Metalevel)args[0];
Object value = args[1];
Related Work:
Reflection in Java.
• MetaXa and Kava enable behavioral reflection
in Java, whereas JavAssist enable structural
reflection.
• JavAssist can be used to achieve behavioral
reflection, such as with MetaXa and Kava.
• Kirby’s system, allows a class definition at
load time. It doesn’t support class redefining.
Related Work:Compile-Time
MetaObject Protocol.
• Another architecture enabling structural
reflection without modifying an existing
runtime system is OpenJava.
• OpenJava was designed mainly for off-line
use at compile time.
Related Work:Compile-Time
MetaObject Protocol.
• OpenJava is source-code based.
• OpenJava alterations are on source code
level.
• OpenJava involves a performance overhead
due to source code manipulations.
On the other hand it results with a finegrained source code.
Related Work:Compile-Time
MetaObject Protocol.
• JavAssist is bytecode based and doesn’t
need source code( which is not always
available).
• No performance overhead: the code is
already compiled, therefore JavAssist
achieves shorter loading time.
• JavAssist runs 10 times faster than
OpenJava.
Related Work: Bytecode
Translators.
• JOIE and JavaClass API provide
functionality similar to JavAssist.
• Using them, the programmer is required to
have a deep understanding of the Java byte
code.
• JavAssist provides source-level abstraction
for manipulating byte code in a safe
manner.
Related Work: Others.
• OpenJIT: allows a Java program to control
how byte code is compiled into native code.
It provides better flexibility with method
body redefinition, but doesn’t allow to add a
new method or field to the class.
Conclusions.
• JavAssist is an extension to the Java
reflection API.
• It enables structural reflection in Java,
allows to alter a given class definition and
to dynamically define a new class.
• Language extensions are more easily
implemented with structural reflection than
with behavioral reflection.
Conclusions (Cont.)
• JavAssist is portable.
• JavAssist provides source-level abstraction
for manipulating byte code in a safe
manner, while byte code translators, such as
JOIE and the JavaClass API, provide no
higher-level abstraction.
• JavAssist processes byte code.
• OpenJava processes source code.
Conclusions (Cont.)
• The architecture of JavAssist can be applied
to other object-oriented languages if a
compiled binary program includes enough
symbolic information to construct a class
object.
• API must be individually designed for each
language to allow class alteration definition
in a safe and meaningful manner.