Technology for modifying Java class File Using ASM-adding class methods

Source: Internet
Author: User

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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.