In the previous post, we went over the
CtMethod classes and how to add code to the beginning and end of a method. In this post, we will cover the dynamic creation and addition of classes, methods, and fields.
In this post, we are going to start with a fairly complex piece of code, and I will then break it down into steps.
$ javac -classpath /path/to/javassist.jar: Inst3.java HelloWorld.java $ java -cp /path/to/javassist.jar: Inst3 Hello World! Goodbye world ------- Hello New World TestName
Compared to the code from the previous post, only a few lines are the same/similar, while the majority of the code is new. The first new lines of code are the pair consisting of
CtClass nhw_ctc = pool.makeClass("NewHelloWorld") and
nhw_ctc.setSuperclass(hw_ctc). They create a new class called
NewHelloWorld and set it to extend from the
HelloWorld class respectively.
The next two lines, `CtField f1 = CtField.make("private String name;", nhw_ctc)` and `nhw_ctc.addField(f1)` are used to create and add a new field, `private String name`, to the `NewHelloWorld` class. Next is a block of code:
This block creates and adds a constructor for
NewHelloWorld that will the field we just created for every new
Next are two blocks of code:
These create two methods and add them both to the
NewHelloWorld class. However, one of the methods,
void do1() already exists in the super class,
HelloWorld. The addition of this new
void do1() method causes it to override the one in the super class. Therefore any calls to this method in
NewHelloWorld will use the new
void do1() instead of the original one.
Now, knowing all of this, the output of the code can be easily explained.</p
Hello World! Goodbye world ------- Hello New World TestName
The first two lines are what they are because we did not modify the
HelloWorld class. However, in the new class
NewHelloWorld, we have overrided the
void do1() method such that the new one calls
System.out.println("Hello New World") and then calls the other new method that we added to
do3() simply prints out the value of the new field,
name, that was added to
NewHelloWorld. If you remember, the new constructor that we added to
name to the string “TestName”.
While this all may seem easy now (hopefully), it is important to note the ordering of the code. Because each piece of code that we added is compiled in the corresponding
make(java.lang.String src, CtClass declaring) method, the referenced values in the lines of code must already exist before each of these
make methods are run, or else a
CannotCompileException will be thrown. Because of this, the constructor and
do3() had to be created after the field was added because they referenced said field; and
do1() had to be created after
do3() was added because it made a call to