有了前幾篇關于BCEL的使用,現(xiàn)在API轉換的問題其實很簡單了
實際API轉換要做的比這個例子要復雜些,涉及到包名,類名,方法名稱等的變化。把常量池變化搞清楚就夠了
假如這是APIa中的一個類
實際只提供APIa的jar包,不提供源代碼










如下是APIb的相對應的類,注意兩個APIa提供的類層次結構,類的名稱已經方法的名稱是一致的










現(xiàn)在有一個應用程序使用的是APIa的類來寫的,并且只提供classes文件,
假如現(xiàn)在把此應用程序放在另一臺機器上運行,但是此機器上只能提供APIb的jar包,要想此應用程序能夠在此機器上運行,則要修改應用程序的classes字節(jié)碼。
應用程序的代碼如下:


























則要調用sb.add(a, b);的地方將方法的參數(shù)改為整型的
本來的指令序列如下
ldc "1"
ldc "2"
invokevirtual one.api.MyAPITest.add (Ljava/lang/String;Ljava/lang/String;)I
則將字節(jié)碼的內容加入
ldc "1"
invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I
ldc "2"
invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I
invokevirtual one.api.MyAPITest.add (II)I
紅色的指令是將操作數(shù)棧的棧頂元素由字符串改變?yōu)檎?br /> 并且還需要把調用的方法的新的方法簽名加入到常量池Constant_Pool中
1,這個在原來的指令序列中插入轉換指令需要插入的地方,但方法的參數(shù)比較明確時如add("1","2")或者add(s1,s2),s1,s2是局部變量,這個插入的地方比較好早。但是當方法的參數(shù)是直接調用其他方法的而產生返回結果時,還需要往指令前找其他方法的調用指令以及這個其他方法有幾個參數(shù),在這個其他方法調用后將這個其他方法的返回結果進行整型轉換。
說的有的亂,假如main方法中為如下時























上面的指令序列為如下:



















invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I

invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I




























invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I




invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I










invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I




invokestatic java.lang.Integer.parseInt(Ljava/lang/String;)I





















看int resultone = sb.add(temp, "33");
要找對應的這個插入地方,首先需要判斷第一個參數(shù)是局部變量使用的aload指令,第二個參數(shù)是直接LDC的
而對于
int resultfour = sb.add(StringUtil.createStringTwo("23", "34"),StringUtil.createStringThree("12", "23", "34"));
add的參數(shù)都是由方法調用的,需要知道在調用add的指令前有幾個invokeXXX指令,然后判斷這些指令有幾個參數(shù),然后選擇合適的地方來插入,總之要根據(jù)方法調用的參數(shù)個數(shù)往前找插入的地方,這個雖然可以實現(xiàn),但是實現(xiàn)起來比較麻煩,不是一個好的辦法。
2.我比較推崇的方法時,但調用add時,此時但卻操作棧的前幾個數(shù)肯定是add的參數(shù),只需要對這些數(shù)進行轉換即可,但是要創(chuàng)建額外的局部變量來保存中間結果,當參數(shù)都轉換完時,在把這些自己創(chuàng)建的局部變量壓入操作棧中,這些操作都在add所對應的invokevirtual指令前,當調用invokevirtual時,操作數(shù)棧的前幾個元素已經是整型了












































































































































































































































































改變字節(jié)碼的片段
129: aload_1
130: ldc "23" (59)
132: ldc "34" (61)
134: invokestatic client.StringUtil.createStringTwo (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; (63)
137: ldc "12" (67)
139: ldc "23" (59)
141: ldc "34" (61)
143: invokestatic client.StringUtil.createStringThree (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; (69)
146: invokestatic java.lang.Integer.parseInt (Ljava/lang/String;)I (98)
149: istore %13
151: invokestatic java.lang.Integer.parseInt (Ljava/lang/String;)I (98)
154: iload %13
156: invokevirtual one.api.MyAPITest.add (II)I (23)