1

最初に私の目標を説明させてください...メソッド本体の一部を変更する必要があります。つまり、メソッド内にはいくつかの呼び出しがありますが、これらの呼び出しの 1 つだけを変更して、1 つではなく 2 つのパラメーターを使用する必要があります。メソッド本体を取得することを考えたメソッド内で残りをすべて同じに保ちたい、この特定の呼び出しを正規表現で変更して、変更して元に戻したい。

それを行う良い方法だとしましょう...どうすればメソッド本体を取得できますか?

どんな提案でも本当に感謝します

ありがとう

ラファエル・モイタ

4

1 に答える 1

2

今日、クラスの静的初期化子にいくつかの変更を加える必要がありましたが、Javaasistを使用して行うことができます。でもそれはかなり難しいです。Javaバイトコードの生成/処理について少なくともある程度の知識が必要です(コンパイル後はソースがなくなります)。

このウィキペディアのページはおそらく便利です:http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings。これには、すべてのJavaバイトコード命令、それらが取るパラメーター、およびそれらがスタック上で行うことのリストが含まれています。

コードは次のとおりです(Groovyですが、Javaへの変換は非常に簡単です)。それが行うことは、静的クラス初期化子のバイトコードを通過し、oldFieldName以前にバイトコードで名前が変更された静的へのすべての割り当て命令を削除することです。お役に立てば幸いです。

def oldFieldName = "removedField"
def cp = ClassPool.getDefault()
//Create new class out of name and bytes
cp.insertClassPath(new ByteArrayClassPath(name, bytes))

def initializer = cc.classInitializer;                                                    
def mi = initializer.getMethodInfo();                                                     
def ca = mi.getCodeAttribute();                                                           

def ci = ca.iterator()                                                                    
//Let's check all bytecode operations in static initializer                               
while (ci.hasNext()) {                                                                    
    def index = ci.next()                                                                 
    int op = ci.byteAt(index)                                                             
    //PUTSTATIC is a bytecode instruction to assign value from stack to static variable   
    if (op == Opcode.PUTSTATIC) {                                                         
        //Address of target variable is calculated like this                              
        def targetFieldAddr = (ci.byteAt(index + 1) << 8) + ci.byteAt(index + 2)          
        def fieldrefName = mi.getConstPool().getFieldrefName(targetFieldAddr)             
        if (fieldrefName == oldFieldName) {                                               
            //Ok, so it's an assignment to renamed variable                               
            //Let's change assignemt to pop from stack (POP2 -> pop long/double value)           
            //We have to remove it or stack won't be valid                                   
            ci.writeByte((byte) Opcode.POP2, index);                                      
            //PUTSTATIC takes 2 arguments so we have to cleare them out          
            //or they will be used as bytecode instructions and probably invalidate class
            ci.writeByte((byte) Opcode.NOP, index + 1);                                   
            ci.writeByte((byte) Opcode.NOP, index + 2);                                   
    }                                                                                 
}                                                                                     

cc.defrost()
cc.detach()

別のヒント: JDKのjavapツールを使用して、変更する前にコンパイル済みクラスを逆アセンブルし、生成したバイトコードと比較します。この方法でバグを見つけるのは簡単です。そのように変更したいバイトコード命令を見つけることもできます。

于 2012-10-20T01:04:45.237 に答える