It is very convenient to use the ASM package to modify the class file, but unfortunately, ASM does not provide a ready-made method modification tool, so we can use the powerful bytecode operation capability provided by it, do it yourself:
The basic idea is as follows: assume that the operation class is a, and assume that the method to be added is Ma. To facilitate the operation, construct Class B and add the MA method of Class B to Class, with this idea, you can quickly implement the following code:
Bytes ---------------------------------------------------------------------------------------------------------------
First, construct a visitor to add the method MA:
Public class bytecodeclassmethodadder extends classadapter {
// Method nodes for appending operation
Private final list <methodnode> methodnodestoappend;
/**
* Construction for bytecode class method adder operation
*
* @ Param CV
* @ Param methodnodes
*/
Public bytecodeclassmethodadder (final classvisitor CV, list <methodnode> methodnodes ){
Super (CV );
// All method nodes needed to append for current class
This. methodnodestoappend = methodnodes;
}
/**
* Visit end of this adapter for current class
*
*/
@ Suppresswarnings ("unchecked ")
Public void visitend (){
For (methodnode Mn: This. methodnodestoappend ){
List Exceptions = Mn. exceptions;
String [] earray = NULL;
If (exceptions. Size ()> 0 ){
Earray = new string [exceptions. Size ()];
For (INT I = 0; I <exceptions. Size (); I ++ ){
String exception = (string) Exceptions. Get (I );
Earray [I] = exception;
}
}
Mn. Accept (CV); // Add this method node to the visitor operation
}
// Overload the visiting operation
Super. visitend ();
}
}
Bytes -----------------------------------------------------------------------------------------------------------
Then construct the operation class for the extraction method from another class B:
Public class bytecodeclassfilterutil implements ibytecodecontainer {
Private classnode = NULL;
/**
* Bytecode class filter utility construction
*
* @ Param classfile
* @ Param op
* @ Throws ioexception
*/
Public bytecodeclassfilterutil (final string classfile) throws ioexception {
Fileinputstream FCM = new fileinputstream (classfile );
Classreader Cr = new classreader (FCM );
Bytecodeclassfilter CA = new bytecodeclassfilter (null );
Cr. Accept (Ca, classreader. expand_frames );
If (FS! = NULL ){
FCM. Close ();
}
}
/**
* Bytecode class filter utility construction
*
* @ Param classfile
* @ Param op
* @ Throws ioexception
*/
Public bytecodeclassfilterutil (File classfile) throws ioexception {
Fileinputstream FCM = new fileinputstream (classfile );
Classreader Cr = new classreader (FCM );
Bytecodeclassfilter CA = new bytecodeclassfilter (null );
Cr. Accept (Ca, classreader. expand_frames );
If (FS! = NULL ){
FCM. Close ();
}
}
/**
* Get a specified class node instance for current bytecode class filter Utility
*
* @ Return
*/
Public classnode getclassnode (){
Return this. classnode;
}
/**
* Get a specified field node by a specified name pattern and description Pattern
*
* @ Param name
* @ Return
*/
@ Suppresswarnings ("unchecked ")
Public list <fieldnode> getfieldnode (string namepattern, string descpattern ){
List <fieldnode> returnnodes = new arraylist <fieldnode> ();
List fields = This. classnode. fields;
If (Fields! = NULL ){
For (Object ofield: fields ){
Fieldnode field = (fieldnode) ofield;
Boolean blnnamematch = true;
Boolean blndescmatch = true;
If (namepattern! = NULL ){
Blnnamematch = pattern. Matches (namepattern, field. Name );
}
If (descpattern! = NULL ){
Blndescmatch = pattern. Matches (descpattern, field. DESC );
}
If (blnnamematch & blndescmatch ){
Returnnodes. Add (field );
}
}
}
Return returnnodes;
}
/**
* Get a specified method name or a list of them.
*
* @ Param name
* @ Param description
* @ Return
*/
@ Suppresswarnings ("unchecked ")
Public list <methodnode> getmethodnode (string namepattern, string descpattern ){
List <methodnode> returnnodes = new arraylist <methodnode> ();
List methods = This. classnode. methods;
If (methods! = NULL ){
For (Object omethod: Methods ){
Methodnode method = (methodnode) omethod;
Boolean blnnamematch = true;
Boolean blndescmatch = true;
If (namepattern! = NULL ){
Blnnamematch = pattern. Matches (namepattern, method. Name );
}
If (descpattern! = NULL ){
Blndescmatch = pattern. Matches (descpattern, method. DESC );
}
If (blnnamematch & blndescmatch ){
Returnnodes. Add (method );
}
}
}
Return returnnodes;
}
/**
* Get all of the field descriptions for a specified class
*
* @ Return
*/
@ Suppresswarnings ("unchecked ")
Public list <string> getfielddescription (){
List <string> desclist = new arraylist <string> ();
List fields = This. classnode. fields;
If (Fields! = NULL ){
For (Object ofield: fields ){
Fieldnode field = (fieldnode) ofield;
Stringbuilder sb = new stringbuilder ();
SB. append (field. Name). append (":"). append (field. DESC );
Desclist. Add (sb. tostring ());
}
}
Return desclist;
}
/**
* Get all of the method list for a specified class
*
* @ Return
*/
@ Suppresswarnings ("unchecked ")
Public list <string> getmethoddescription (){
List <string> desclist = new arraylist <string> ();
List methods = This. classnode. methods;
If (methods! = NULL ){
For (Object omethod: Methods ){
Methodnode method = (methodnode) omethod;
Stringbuilder sb = new stringbuilder ();
SB. append (method. Name). append (":"). append (method. DESC );
Desclist. Add (sb. tostring ());
}
}
Return desclist;
}
/**
* Bytecode class filter extend from class adpater class.
*
*/
Class bytecodeclassfilter extends classadapter {
// Construction call for current class
Public bytecodeclassfilter (final classvisitor cv ){
Super (New classnode (){
Public void visitend (){
If (CV! = NULL ){
Accept (CV );
}
}
});
}
// Execute the next operation after this visit ending
Public void visitend (){
Classnode = (classnode) CV;
}
}
}
Bytes ------------------------------------------------------------------------------------------------
Construct the call function to implement the "transfer" function of the method:
Public void addmethodtoclass (string SRC, string des, string combine, string namefilter, string descfilter)
Throws ioexception {
Bytecodeclassfilterutil util = new bytecodeclassfilterutil (SRC );
List <methodnode> methods = util. getmethodnode (namefilter, descfilter );
// Visitor current class
If (methods. Size () = 0 ){
System. Out. println ("error: No method is chosen out by the filter .");
} Else {
Classwriter CW = new classwriter (0 );
Bytecodeclassmethodadder adder = new bytecodeclassmethodadder (CW, methods );
Fileinputstream FCM = new fileinputstream (DES );
Classreader Cr = new classreader (FCM );
Cr. Accept (adder, classreader. expand_frames); // need to expand frames for current end user
If (FS! = NULL ){
FCM. Close ();
}
// Convert the specified method into current class
Byte [] bytearray = CW. tobytearray ();
Fileoutputstream Fos = new fileoutputstream (combine );
FOS. Write (bytearray );
FOS. Flush ();
FOS. Close ();
}
}
Bytes ------------------------------------------------------------------------------------
Last Mount interface:
Addmethodtoclass (sourcefile, targetfile, destfile, namefilter, descfilter );
Note: sourcefile = B. Class;
Targetfile = A. Class;
Destfile = merged a. Class
Namefilter and descfilter support regular expressions and can be null. If they are null, all methods are added;
You can test it and you will find that the original code "Migration" is so easy.