28
JavAssist X.java X.class Class Loade r My Loader X compile lo ad sist enables preload byte code modific

JavAssist X.java X.class Class Loader My Loader X compile load JavAssist enables preload byte code modification

Embed Size (px)

Citation preview

JavAssistX.java

X.class

ClassLoader

My Loader

X

compile

load

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.class

X’

My Loader

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

•Introspection•Alteration.•Adding a new Member.•Altering a Method Body.•Javassist Class Loader.

Class{

Fields

Constructors

Methods{

CtClass{

CtFields

CtMethods

CtMethods{

CtClass Introspection

CtField & CtMethod Introspection

Alteration

Example: addMethodpublic class Xvector extends java.util.vector{

public void add(X e){super.addElement(e);

{{

CtMethod m = // method add() in XVector CtClass c = // class StringVectorClassmap = 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

CtMethod m = // method which body is to be changedCodeConverter conv = new CodeConverter();Conv.replaceNew(Xclass, Yclass, “create” );m.instrument(conv);

M( … ){…Xclass xclass = new Xclass(3,4);…

{

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()); return;

}{

{

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 MyMetaObject(this);

public MetaObject _getMetaObject() { return _MetaObject; } public int orig_m(int x) { return x + f; }

public static int read_f(Object target) {/*notify a MetaObject. */ } public static void write_f(Object target, int value){

*/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];

target._getMetaObject().trapFieldWrite(name, value);

}

}

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 fine-grained 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.