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

Source: Internet
Author: User

It is very convenient to use the ASM package to modify the class file, but unfortunately, ASM does not provide ready-made tools, so we can use the powerful bytecode operation capability provided by it to do it ourselves:

The basic idea is as follows: assume that the operation class is a, and assume that the attribute to be added is Pa. For convenience of operation, construct Class B and add the PA attribute of Class B to Class, with this idea, you can quickly implement the following code:

Bytes ---------------------------------------------------------------------------------------------------------------

First, construct visitor to add the member variable PA:

Public class bytecodeclassfieldadder extends classadapter {

Private final list <fieldnode> fieldnodestoappend;
 
/**
* Construct for current class
*
* @ Param CV
* @ Param fieldnode
*/
Public bytecodeclassfieldadder (classvisitor CV, list <fieldnode> fieldnodes ){
Super (CV );
This. fieldnodestoappend = fieldnodes;
}
 
/**
* Visit to the end for current class, append to the vistor class
*
*/
Public void visitend (){
For (fieldnode FN: This. fieldnodestoappend ){
FN. Accept (CV );
}
Super. visitend ();
}
 
}

 

Bytes ---------------------------------------------------------------------------------------------------------------

Then construct the operation class for extracting members 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 property "transfer" function:

Public void addfieldtoclass (string SRC, string des, string combine, string namefilter, string descfilter)
Throws ioexception {
Bytecodeclassfilterutil util = new bytecodeclassfilterutil (SRC );
List <fieldnode> fields = util. getfieldnode (namefilter, descfilter );

// Visitor current class
If (fields. Size () = 0 ){
System. Out. println ("error: no field is chosen out by the filter .");
} Else {
Classwriter CW = new classwriter (0 );
Bytecodeclassfieldadder adder = new bytecodeclassfieldadder (CW, fields );
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 ();
}
}

 

-------------------------------------------------------------------

Last Mount interface:

Addfieldtoclass (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 fields are added;

 

The following is a small question:

If it is a static variable that only copies the declared part and does not copy the assigned part, what is the reason?

It turns out that I forgot to copy the cinit () function, but this is part of the next part.

 

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.