java - Modifying line numbers in Javassist -
so have been using javassist bit lately, , have run question haven't been able find answer to. insertat method of ctmethod allows insert code @ specific line number, overwrite line or keep it, , how make opposite of default? have application modifies source before runtime javassist, based on 'hooks' in xml file. want make line can overridden, or line can placed above line instead of overriding it. there hackish ways that, i'd rather use proper way.
the easy part
the method insertat(int linenumber, string src) present in ctmethod object allows injecting code written in src before code in given line.
for instance, take following (simple) example program:
public class testsubject { public static void main(string[] args) { testsubject testsubject = new testsubject(); testsubject.print(); } private void print() { system.out.println("one"); // line 9 system.out.println("two"); // line 10 system.out.println("three"); // line 11 } }
by coding (keep in mind method variable must ctmethod representation of print method):
// notice said line 10, sysout of "two" method.insertat(10, true, "system.out.println(\"one , half\");");
will inject new sysout instruction in class. output of new class be:
1 1 , half 2 3
the hard part
javassist not provide easy way remove line of code, if want replace you'll have no choice hack way through.
how it? well, let me introduce new friend (if don't know yet), codeattribute object.
the codeattribute object responsible holding bytecode represents method flow besides code attribute has attribute called linenumberattribute helps map line numbers bytecode array. summing object has need!
the idea in following example quite simple. relate bytes in bytecode array line should removed , substitute bytes no operation code.
once again, method ctmethod representation of method print
// let's erase sysout "two" int linenumbertoreplace = 10; // access code attribute codeattribute codeattribute = method.getmethodinfo().getcodeattribute(); // access linenumberattribute linenumberattribute linenumberattribute = (linenumberattribute) codeattribute.getattribute(linenumberattribute.tag); // index in bytecode array instruction starts int startpc = linenumberattribute.tostartpc(linenumbertoreplace); // index in bytecode array following instruction starts int endpc = linenumberattribute.tostartpc(linenumbertoreplace+1); system.out.println("modifying " + startpc + " " + endpc); // let's bytecode array byte[] code = codeattribute.getcode(); (int = startpc; < endpc; i++) { // change byte no operation code code[i] = codeattribute.nop; }
running modification in original testsubject class, result in injected class following output:
1 3
summing up
when have need add line , still keeping existing one, need use example given in the easy part if want replace line, have first remove existing line using example given in the hard part , inject new line using 1st example.
also keep in mind in examples assumed comfortable basics of javassist showing juicy parts, instead of deal. that's why, instance, in examples there no ctclass.writefile... still need it, left out because expect should know have it.
if need in code examples, ask. i'll glad help.
Comments
Post a Comment