ASM3.0學習(三)

2.3工具
除了ClassVisitor接口,以及與之相關的三個組件ClassReader ClassAdapter和ClassWriter,ASM在org.objectweb.asm.util包中提供了一些工具用來幫助開發類生成器或者適配器,這些工具在運行時並不須要。ASM提供了一些實用類用來在運行時操做內部名稱,類型描述符以及方法描述符。全部的這些工具將在下面介紹。
2.3.1類型
就像在前面章節中見到的,ASM API將編譯後的class中的java類型之內部名稱或者類型描述符的方式展示出來。固然,也能夠將這些類型還原成源代碼中定義的樣子,這樣就更便於閱讀。可是,這須要在ClassReader和ClassWriter之間進行系統轉換,可是這會下降性能。這就是爲何ASM沒有透明地轉換內部名稱和類型描述符爲源代碼中對等的形式。儘管如此,ASM仍是提供了Type類用來在須要的時候手工地進行轉換。
一個Type對象表明了一個java類型,它能夠經過類型描述符或者Class對象來構造。這個Type類也包含了一些靜態變量,用來表示基本類型,例如Type.INT_TYPE是int類型的Type對象。
getInternalName方法返回一個Type的內部名稱,例如,Type.getType(String.class).getInternalName()返回了String類的內部名稱」java/lang/String」.這個方法只能用於類或者藉口類型。
getDescriptor方法返回一個Type的描述符,例如,你可使用Type.getType(String.class).getDescriptor()來代替」Ljava/lang/String;」。或者,使用Type.INT_TYPE.getDescriptor()來代替I。
Type類也提供了一些靜態方法用來獲取一個方法的參數的Type對象和返回值的Type對象,主要是經過它的類型描述符或者java.lang.reflect.Method對象來得到。例如,Type.getArgumentTypes(「(I)V」)返回一個包含Type.INT_TYPE的數組,一樣地Type.getReturnType(「(I)V」)返回一個Type.VOID_TYPE對象。
2.3.2 TraceClassVisitor
爲了檢查類的生成或者轉換是否如你指望,單靠ClassWriter返回的字節數組是沒有多大幫助的,由於它不可讀。相比較而言,一個文本表示更易於閱讀和使用,而這就是TraceClassVisitor提供的。這個類,就如它的名字暗示的同樣,實現了ClassVisitor藉口,而且構造解析過的類的文本表示。所以,你可使用TraceClassVisitor來替代ClassWriter,這樣你能夠跟蹤真正生成的是什麼。更好的辦法是同時使用這二者,TraceClassVisitor能夠跟蹤代碼生成,除此以外,它也能夠將全部的調用委託給另一個visitor,如ClassWriter:
ClassWriter cw = new ClassWriter(0);
TraceClassVisitor cv = new TraceClassVisitor(cw, printWriter);
cv.visit(...);
...
cv.visitEnd();
byte b[] = cw.toByteArray();
上面的代碼建立了一個TraceClassVisitor,而後委託全部對它的調用給cw,而且將對這些方法的調用以文本方式交給printWriter來打印。例如,在2.2.3章節中的例子使用TraceClassVisitor會輸出以下內容:
// class version 49.0 (49)
// access flags 1537
public abstract interface pkg/Comparable implements pkg/Mesurable {
// access flags 25
public final static I LESS = -1
// access flags 25
public final static I EQUAL = 0
// access flags 25
public final static I GREATER = 1
// access flags 1025
public abstract compareTo(Ljava/lang/Object;)I
}
注意,爲了弄清楚在轉換鏈中到底發生了什麼,你能夠在生成類或者轉換鏈過程的任何點使用TraceClassVisitor,而不只僅是在ClassWriter以前使用。注意,經過這個類生成的類的文本表示能夠經過String.equals()很容易地進行比較。
2.3.3 CheckClassAdapter
ClassWriter並不會檢查它的方法調用是否按照合適的順序以及參數是否有效。這樣就可能生成無效的代碼,而被java虛擬機的驗證工具所拒絕。爲了儘量地檢測出這些錯誤,可使用CheckClassAdapter。和TraceClassVisitor同樣,這個類也實現了ClassVisitor接口,它也會將對它的方法調用委託給其餘的ClassVisitor,例如一個TraceClassVisitor或者ClassWriter。儘管如此,除了打印類的文本表示,這個類會在將方法調用委託給下一個ClassVisitor以前,檢查對它的方法調用順序是否合理,以及參數是否有效。若是發生錯誤,將會拋出IllegalStateException或者IllegalArgumentException。
爲了檢查一個類,而且打印它的文本表示,最終建立一個字節數組,你能夠參考下面的代碼:
ClassWriter cw = new ClassWriter(0);
TraceClassVisitor tcv = new TraceClassVisitor(cw, printWriter);
CheckClassAdapter cv = new CheckClassAdapter(tcv);
cv.visit(...);
...
cv.visitEnd();
byte b[] = cw.toByteArray();
注意,若是這些ClassVisitor的順序不一樣,那麼它們會以不一樣的順序執行。例如,下面的代碼會致使在跟蹤代碼之後再檢查類。
ClassWriter cw = new ClassWriter(0);
CheckClassAdapter cca = new CheckClassAdapter(cw);
TraceClassVisitor cv = new TraceClassVisitor(cca, printWriter);
就像TraceClassVisitor同樣,爲了檢查類是否有效,你也能夠在生成類或者轉換類的鏈的任
何節點使用CheckClassAdapter,而不只僅是在ClassWriter以前。
2.3.4 ASMifierClassVisitor
這個類也實現了ClassVisitor接口,它的每一個方法會打印出調用它的java代碼。例如,調用visitEnd會打印出cv.visitEnd();,結果是,當這個visitor解析一個類時,它會打印出使用ASM來生成這個類的源代碼。當你使用這個類去解析一個存在的類時,你會發現它頗有用。例如,若是你不知道如何使用ASM來生成一些編譯後的類,那麼你能夠先寫出這些類的源代碼,而後使用javac來編譯,再而後使用ASMifierClassVisitor來解析,這樣就可以獲得使用ASM來生成這些類的源代碼了。
ASMifierClassVisitor能夠經過命令行直接使用,以下面的例子:
java -classpath asm.jar:asm-util.jar \
org.objectweb.asm.util.ASMifierClassVisitor \
java.lang.Runnable
生成的代碼通過縮進之後,就是下面的代碼:
package asm.java.lang;
import org.objectweb.asm.*;
public class RunnableDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
"java/lang/Runnable", null, "java/lang/Object", null);
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "run", "()V",
null, null);
mv.visitEnd();java

相關文章
相關標籤/搜索