Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analysis of javassist examples of Java bytecode programming

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains the "Java bytecode programming javassist case analysis", the content of the article is simple and clear, easy to learn and understand, the following please follow the editor's ideas slowly in depth, together to study and learn "Java bytecode programming javassist case analysis"!

Introduction to Javassist (1) what is Javassist

Javassist is a class library that can dynamically edit Java bytecode. It can define a new class when the Java program is running and load it into JVM; it can also modify a class file when the JVM loads. Javassist allows users to edit class files without having to worry about bytecode-related specifications.

(2) Javassist core API

Each class that needs to be edited in Javassist corresponds to an instance of CtCLass. CtClass means compile-time compile time class, which is stored in Class Pool (Class poll is a container for CtClass objects).

CtField and CtMethod in CtClass correspond to fields and methods in Java, respectively. You can add fields and modify methods to the class through the CtClass object.

(3) simple examples

In order to reduce the complexity of the demonstration, the examples and subsequent operations are carried out under the Maven project, because we can directly introduce dependencies to achieve our goal of guiding the package, which is very convenient, without having to download the jar package and then import it manually.

1. Create a maven project

If you are using IDEA, you can be like me; if it is other tools, you can create your own Baidu, or create it according to your own experience.

2. Create a test class with the following code:

Package com.ssdmbbl.javassist;import javassist.*;import java.io.IOException;/** * @ author zhenghui * @ description: Javassist demo test * @ date 6:38 afternoon on 2021-4-6 * / public class JavassistTest {public static void main (String [] args) throws CannotCompileException, IOException {ClassPool cp = ClassPool.getDefault (); CtClass ctClass = cp.makeClass ("com.ssdmbbl.javassist.Hello"); ctClass.writeFile (". /");}}

When you run this code, you can see that a "com.ssdmbbl.javassist" package has been created in the root directory of the project, and the java file "Hello.java" has been created under this package.

The contents are as follows:

Package com.ssdmbbl.javassist;public class Hello {public Hello () {}} II. Javassist operation bytecode example

Recall that if we were to operate normally on a Java, what would we do?

1. We will add fields to a class

2. We will add methods to a class

There seems to be nothing else. The rest is to write code in the method.

(1) add a new method

Let's continue to apply the code of the simple example above and add a new method based on it.

The new method is named "hello1", passes two parameters of type int and double, and does not return a value.

Package com.ssdmbbl.javassist;import javassist.*;import java.io.IOException;import java.net.URL / * * @ author zhenghui * @ description: Javassist uses the demo test * @ date 6:38 on 2021-4-6 * / public class JavassistTest2 {public static void main (String [] args) throws CannotCompileException, IOException {/ / find the path to this file and save it with URL resource = JavassistTest2.class.getClassLoader (). GetResource ("); String file = resource.getFile () System.out.println ("File Storage path:" + file); ClassPool cp = ClassPool.getDefault (); CtClass ctClass = cp.makeClass ("com.ssdmbbl.javassist.Hello") / / create a class named "hello", pass parameters in the order of (int,double), and have no return value of the class / * CtMethod (...) source code: public CtMethod (the return value type of the CtClass returnType,// method) String mname, / / (method name) what is the name of the method CtClass [] parameters, / / what is the type of parameter passed in by the method CtClass declaring / / to which class is added) {.} * / CtMethod ctMethod = new CtMethod (CtClass.voidType, "hello") New CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass) / / set the permission of the hello method to public ctMethod.setModifiers (Modifier.PUBLIC); / / add this method ctClass.addMethod (ctMethod) to ctClass; / / write local ctClass.writeFile (file);}}

After execution, you can view the generated code:

As you can see, we do not specify the name of the parameter, but also give the name of generating var1, var2 and so on.

Var1 and var2 are actually the names stored in the class variable table.

Package com.ssdmbbl.javassist;public class Hello {public void hello1 (int var1, double var2) {} public Hello () {}}

The type of return value that can be set:

Public static CtClass booleanType;public static CtClass charType;public static CtClass byteType;public static CtClass shortType;public static CtClass intType;public static CtClass longType;public static CtClass floatType;public static CtClass doubleType;public static CtClass voidType; (2) add a variable URL resource = JavassistTest2.class.getClassLoader (). GetResource ("); String file = resource.getFile (); System.out.println (" file storage path: "+ file); ClassPool cp = ClassPool.getDefault (); CtClass ctClass = cp.makeClass (" com.ssdmbbl.javassist.Hello ") / / add a hello1 method CtMethod ctMethod = new CtMethod (CtClass.voidType, "hello1", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); ctMethod.setModifiers (Modifier.PUBLIC); ctClass.addMethod (ctMethod); / / add a variable of type int named CtField ctField = new CtField (CtClass.intType, "value", ctClass); ctField.setModifiers (Modifier.PRIVATE); ctClass.addField (ctField); ctClass.writeFile (file)

Then the content after execution is as follows:

Package com.ssdmbbl.javassist;public class Hello {private int value; public void hello1 (int var1, double var2) {} public Hello () {}} (3) add get and set methods to variables

The code is modified as follows:

Public static void main (String [] args) throws CannotCompileException, IOException {URL resource = JavassistTest2.class.getClassLoader () .getResource (""); String file = resource.getFile (); System.out.println ("File Storage path:" + file); ClassPool cp = ClassPool.getDefault (); CtClass ctClass = cp.makeClass ("com.ssdmbbl.javassist.Hello") / / add a hello1 method CtMethod ctMethod = new CtMethod (CtClass.voidType, "hello1", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); ctMethod.setModifiers (Modifier.PUBLIC); ctClass.addMethod (ctMethod); / / add a variable of type int named CtField ctField = new CtField (CtClass.intType, "value", ctClass); ctField.setModifiers (Modifier.PRIVATE) CtClass.addField (ctField); / / add set method CtMethod setValue = new CtMethod (CtClass.voidType, "setValue", new CtClass [] {CtClass.intType}, ctClass) to the value variable; setValue.setModifiers (Modifier.PUBLIC); ctClass.addMethod (setValue); / / add get method CtMethod getValue = new CtMethod (CtClass.intType, "getValue", new CtClass [] {}, ctClass) to the value variable GetValue.setModifiers (Modifier.PUBLIC); ctClass.addMethod (getValue); ctClass.writeFile (file);}

Execution effect:

Package com.ssdmbbl.javassist;public class Hello {private int value; public void hello1 (int var1, double var2) {} public void setValue (int var1) {} public int getValue () {} public Hello () {}} (IV) add code inside the method

Are you curious that there is no code inside the set and get methods, and when the program runs, it is bound to go wrong.

Let's take a look.

What we expected:

Private int value; public void setValue (int var1) {this.value = var1} public int getValue () {return this.value;}

The modifications are as follows:

/ add the set method CtMethod setValue = new CtMethod (CtClass.voidType, "setValue", new CtClass [] {CtClass.intType}, ctClass) to the value variable; setValue.setModifiers (Modifier.PUBLIC); / / set the method body setValue.setBody ("this.value = var1;"); ctClass.addMethod (setValue); / / add the get method CtMethod getValue = new CtMethod (CtClass.intType, "getValue", new CtClass [] {}, ctClass) to the value variable; getValue.setModifiers (Modifier.PUBLIC) / / set method body getValue.setBody ("return this.value;"); ctClass.addMethod (getValue)

Unfortunately, he said that the variable var1 could not be found.

The stack information for reporting an error is as follows:

Exception in thread "main" javassist.CannotCompileException: [source error] no such field: var1

At javassist.CtBehavior.setBody (CtBehavior.java:474)

At javassist.CtBehavior.setBody (CtBehavior.java:440)

At com.ssdmbbl.javassist.JavassistTest2.main (JavassistTest2.java:41)

Caused by: compile error: no such field: var1

We actually mentioned this reason earlier, because when compiling, the variable name will be erased and the parameters passed will be in the order in the local variable table.

If you pass:

Public void test (int a _ line int b _ line int c) {...}

Then the position of a _ rect _ b _ rec corresponds to the position of 1 ~ ~ 2 ~ 3 in the local variable scale.

-| a | 1 | | b | 2 | | c | 3 |

Then we can't use the original name when we get the variable. The parameters in the method are accessed using $1, 2, 2, 2, in Javassist. Instead of using the original name directly

We modify it as follows:

/ add set method CtMethod setValue = new CtMethod (CtClass.voidType, "setValue", new CtClass [] {CtClass.intType}, ctClass) to value variable; setValue.setModifiers (Modifier.PUBLIC); / / set method body setValue.setBody ("this.value = $1;"); ctClass.addMethod (setValue); / / add get method CtMethod getValue = new CtMethod (CtClass.intType, "getValue", new CtClass [] {}, ctClass); getValue.setModifiers (Modifier.PUBLIC) to value variable / / set method body getValue.setBody ("return this.value;"); ctClass.addMethod (getValue)

It turned out to be a success:

Public class Hello {private int value; public void hello1 (int var1, double var2) {} public void setValue (int var1) {this.value = var1;} public int getValue () {return this.value;} public Hello () {}}

One more: modify the body of the hello1 method so that the two parameters passed are added and then assigned to value

/ / add a hello1 method CtMethod ctMethod = new CtMethod (CtClass.voidType, "hello1", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); ctMethod.setModifiers (Modifier.PUBLIC); ctMethod.setBody ("this.value = $1 + $2;"); ctClass.addMethod (ctMethod)

The implementation results are as follows:

Because our value is int,$1, int,$2 is double, so we have made a forced transformation.

Public void hello1 (int var1, double var2) {this.value = (int) ((double) var1 + var2);} (v) insert code before and after the method body

The test code is as follows:

/ add a hello1 method CtMethod ctMethod = new CtMethod (CtClass.voidType, "hello1", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); ctMethod.setModifiers (Modifier.PUBLIC); ctMethod.setBody ("this.value = $1 + $2;"); ctMethod.insertBefore ("System.out.println (" I inserted: "+ $1);"); ctMethod.insertAfter ("System.out.println (" I inserted at the end: "+ $1);"); ctClass.addMethod (ctMethod)

The results are as follows:

Public void hello1 (int var1, double var2) {System.out.println ("I inserted:" + var1); this.value = (int) ((double) var1 + var2); Object var5 = null; System.out.println ("I inserted:" + var1 at the end);}

Third, some examples of special parameters in Javassist are explained.

There are several special identifiers in the official documentation, and there are a few more special identifiers to know.

Identifiers function as $0, $1, $2, 3, 3, 3, … This and method parameters (1mi N is the order of method parameters) $args method parameter array, type Object [] $$all method parameters, for example: M ($$) is equivalent to m ($1) $cflow (…) The control flow variable $r returns the type of result, which is used in cast expressions. W wrapper type, used in cast expressions. The result value returned by $_ is $parameter type object array of type sig java.lang.Class $type type is java.lang.Class return value type $class type is java.lang.Class (1) $0rem "1dint" 2, …

In fact, we have already used this on it. Let's elaborate on it again. $0 represents this,$1, 2, 2, 2, … Which in turn corresponds to the order of the parameters in the method

If there are:

Public void test (int a _ line int b _ line int c) {}

So if you want to quote an and b and c, you need to do this:

CtMethod.setBody ("return $1 + $2 + $3;")

By the way, there is no $0 for static methods, so $0 is not available for static methods.

(II) $args

The $args variable represents an array of all parameters, which is an array of type Object (new Object [] {... }), if there are parameters of the original type in the parameter, it will be converted to the corresponding wrapper type. For example, if the original data type is int, it is converted to java.lang.Integer and then stored in args.

For example, our test code is as follows:

CtMethod ctMethod = new CtMethod (CtClass.voidType, "hello1", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); ctMethod.setModifiers (Modifier.PUBLIC); ctMethod.setBody ("System.out.println ($args);")

The compiled result is as follows:

Public void hello1 (int var1, double var2) {System.out.println (new Object [] {new Integer (var1), new Double (var2)});} (III) $$

Variables are abbreviations of all parameters, which are divided by commas, for example: M (is the abbreviation of all parameters, parameters are separated by commas, for example: M (is the abbreviation of all parameters, parameters are separated by commas, for example: M () is equivalent to: M ($1) .

How to use it?

We often do some code optimization to extract the internal logic of the more complex methods and refine them into a common method.

Or it is used when one method calls another method and the parameters passed by the two methods are the same.

For example, the original java:

Public Object M1 (String name,String age) {... Omit 10000 lines of code logic}

Refined:

The extracted code can also be used in other places (so-called public code).

Public Object M1 (String name,String age) {... Omit 20 lines of code logic return m2 (name,age);} private Object m2 (String name,String age) {.}

So let's create a scene to illustrate the usage.

To put it simply, when one method calls another method, passing full parameters.

CtMethod hello2 = new CtMethod (CtClass.voidType, "hello2", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); hello2.setModifiers (Modifier.PUBLIC); hello2.setBody ("this.value = $1 + $2;"); ctClass.addMethod (hello2); / / add a hello1 method CtMethod hello1 = new CtMethod (CtClass.voidType, "hello1", new CtClass [] {CtClass.intType, CtClass.doubleType}, ctClass); hello1.setModifiers (Modifier.PUBLIC); hello1.setBody ("this.value = $1 + $2;") Hello1.insertAfter ("hello2 ($$);")

You can see that when we hello1 calls hello2, we need to pass all the parameters. At this point, it can be written as a $$method or, of course, as hello2 ($1 heroin 2).

The compiled result:

Public void hello2 (int var1, double var2) {this.value = (int) ((double) var1 + var2);} public void hello1 (int var1, double var2) {this.value = (int) ((double) var1 + var2); Object var5 = null; this.hello2 (var1, var2);} (IV) $cflow (…)

The full name of $cflow is: control flow, which is a read-only variable that returns the depth of the recursive call to the specified method.

Let's demonstrate how to use it by calculating the Fibonacci number of n.

Our correct recursive algorithm code is as follows:

Public int f (int n) {if (n)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report