今日、クラスの静的初期化子にいくつかの変更を加える必要がありましたが、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ツールを使用して、変更する前にコンパイル済みクラスを逆アセンブルし、生成したバイトコードと比較します。この方法でバグを見つけるのは簡単です。そのように変更したいバイトコード命令を見つけることもできます。