# Javassist Tutorial

## 1. Reading and writing bytecode
The class `Javassist.CtClass` is an abstract representation of a class file. A `CtClass` (compile-time class) object is a handle for dealing with a class file.
```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();
```

### Defining a new class
To define a new class from scratch, `makeClass()` must be called on a `ClassPool`.
```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("Point");
```

### Frozen classes
If a `CtClass` object is converted into a class file by `writeFile()`, `toClass()`, or `toBytecode()`, Javassist freezes that `CtClass` object. Further modifications of that `CtClass` object are not permitted. This is for warning the developers when they attempt to modify a class file that has been already loaded since the JVM does not allow reloading a class.

To disallow pruning a particular `CtClass`, `stopPruning()` must be called on that object in advance

### Class search path
```
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/usr/local/javalib");
```

## 2. ClassPool
A `ClassPool` object is a container of `CtClass` objects. Once a `CtClass` object is created, it is recorded in a `ClassPool` for ever. This is because a compiler may need to access the `CtClass` object later when it compiles source code that refers to the class represented by that `CtClass`.

### Avoid out of memory
```
CtClass cc = ... ;
cc.writeFile();
cc.detach();
```
```
ClassPool cp = new ClassPool(true);
// if needed, append an extra search path by appendClassPath()
ClassPool cp = new ClassPool();
cp.appendSystemPath();  // or append another path by appendClassPath()
```

### Cascaded ClassPools
Multiple `ClassPool` objects can be cascaded like `java.lang.ClassLoader`.
```
ClassPool parent = ClassPool.getDefault();
ClassPool child = new ClassPool(parent);
child.insertClassPath("./classes");
```
```
ClassPool parent = ClassPool.getDefault();
ClassPool child = new ClassPool(parent);
child.appendSystemPath();         // the same class path as the default one.
child.childFirstLookup = true;    // changes the behavior of the child.
```

### Changing a class name for defining a new class
```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.setName("Pair");
```
```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
CtClass cc1 = pool.get("Point");   // cc1 is identical to cc.
cc.setName("Pair");
CtClass cc2 = pool.get("Pair");    // cc2 is identical to cc.
CtClass cc3 = pool.get("Point");   // cc3 is not identical to cc.
```

### Renaming a frozen class for defining a new class
Once a `CtClass` object is converted into a class file by `writeFile()` or `toBytecode()`, Javassist rejects further modifications of that `CtClass` object.
```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.writeFile();
CtClass cc2 = pool.getAndRename("Point", "Pair");
```
If `getAndRename()` is called, the `ClassPool` first reads `Point.class` for creating a new `CtClass` object representing `Point` class. However, it renames that `CtClass` object from `Point` to `Pair` before it records that `CtClass` object in a hash table. Thus `getAndRename()` can be executed after `writeFile()` or `toBytecode()` is called on the the `CtClass` object representing `Point` class.

## 3. Class loader
1. Get a `CtClass` object by calling `ClassPool.get()`,
2. Modify it, and
3. Call `writeFile()` or `toBytecode()` on that `CtClass` object to obtain a modified class file.

### 3.1 The toClass method in CtClass
The `CtClass` provides a convenience method `toClass()`, which requests the context class loader for the current thread to load the class represented by the `CtClass` object. To call this method, the caller must have appropriate permission; otherwise, a `SecurityException` may be thrown.
```
public class Hello {
    public void say() {
        System.out.println("Hello");
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("Hello");
        CtMethod m = cc.getDeclaredMethod("say");
        m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
        Class c = cc.toClass();
        Hello h = (Hello)c.newInstance();
        h.say();
    }
}
```

### 3.2 Class loading in Java
In Java, multiple class loaders can coexist and each class loader creates its own name space. Different class loaders can load different class files with the same class name. The loaded two classes are regarded as different ones. This feature enables us to run multiple application programs on a single JVM even if these programs include different classes with the same name.

**Note**: The JVM does not allow dynamically reloading a class. Once a class loader loads a class, it cannot reload a modified version of that class during runtime. Thus, you cannot alter the definition of a class after the JVM loads it. However, the JPDA (Java Platform Debugger Architecture) provides limited ability for reloading a class.

#### Dynamic Class Loading Example
ClassLoader working mechanism:
1. A `ClassLoader` instance checks if the class was already loaded.
2. If not loaded, it delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.
3. If parent class loader cannot load class, it attempt to load the class or resource by itself.

### 3.3 Using javassist.Loader
Javassist provides a class loader `javassist.Loader`. This class loader uses a `javassist.ClassPool` object for reading a class file.
```
public class MyTranslator implements Translator {
    void start(ClassPool pool)
        throws NotFoundException, CannotCompileException {}
    void onLoad(ClassPool pool, String classname)
        throws NotFoundException, CannotCompileException
    {
        CtClass cc = pool.get(classname);
        cc.setModifiers(Modifier.PUBLIC);
    }
}
```
If the users want to modify a class on demand when it is loaded, the users can add an event listener to a `javassist.Loader`.

The event-listener class must implement `javassist.Translator`:
- The method `start()` is called when this event listener is added to a `javassist.Loader` object by `addTranslator() `in `javassist.Loader`.
- The method `onLoad()` is called before `javassist.Loader` loads a class. `onLoad()` can modify the definition of the loaded class.

Note that `onLoad()` does not have to call `toBytecode()` or `writeFile()` since `javassist.Loader` calls these methods to obtain a class file.
```
public class Main2 {
  public static void main(String[] args) throws Throwable {
     Translator t = new MyTranslator();
     ClassPool pool = ClassPool.getDefault();
     Loader cl = new Loader();
     cl.addTranslator(pool, t);
     cl.run("MyApp", args);
  }
}
```

`javassist.Loader` searches for classes in a different order from `java.lang.ClassLoader`. `ClassLoader` first delegates the loading operations to the parent class loader and then attempts to load the classes only if the parent class loader cannot find them. On the other hand, `javassist.Loader` attempts to load the classes before delegating to the parent class loader. It delegates only if:
- the classes are not found by calling `get()` on a `ClassPool` object, or
- the classes have been specified by using `delegateLoadingOf()` to be loaded by the parent class loader.

### 3.4 Writing a class loader
```
public class SampleLoader extends ClassLoader {
    /* Call MyApp.main().
     */
    public static void main(String[] args) throws Throwable {
        SampleLoader s = new SampleLoader();
        Class c = s.loadClass("MyApp");
        c.getDeclaredMethod("main", new Class[] { String[].class })
         .invoke(null, new Object[] { args });
    }

    private ClassPool pool;

    public SampleLoader() throws NotFoundException {
        pool = new ClassPool();
        pool.insertClassPath("./class"); // MyApp.class must be there.
    }

    /* Finds a specified class.
     * The bytecode for that class can be modified.
     */
    protected Class findClass(String name) throws ClassNotFoundException {
        try {
            CtClass cc = pool.get(name);
            // modify the CtClass object here
            byte[] b = cc.toBytecode();
            return defineClass(name, b, 0, b.length);
        } catch (NotFoundException e) {
            throw new ClassNotFoundException();
        } catch (IOException e) {
            throw new ClassNotFoundException();
        } catch (CannotCompileException e) {
            throw new ClassNotFoundException();
        }
    }
}
```

### 3.5 Modifying a system class
The system classes like `java.lang.String` cannot be loaded by a class loader other than the system class loader.

the system classes must be **statically** modified.
```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("java.lang.String");
CtField f = new CtField(CtClass.intType, "hiddenValue", cc);
f.setModifiers(Modifier.PUBLIC);
cc.addField(f);
cc.writeFile(".");
```
```
java -Xbootclasspath/p:. MyApp arg1 arg2...
```
_Note: Applications that use this technique for the purpose of overriding a system class in `rt.jar` should not be deployed as doing so would contravene the Java 2 Runtime Environment binary code license._

### 3.6 Reloading a class at runtime
If the JVM is launched with the JPDA (Java Platform Debugger Architecture) enabled, a class is dynamically reloadable. After the JVM loads a class, the old version of the class definition can be unloaded and a new one can be reloaded again. That is, the definition of that class can be dynamically modified during runtime. However, the new class definition must be somewhat compatible to the old one. **The JVM does not allow schema changes between the two versions.** They have the same set of methods and fields.

Javassist provides a convenient class for reloading a class at runtime. For more information, see the API documentation of `javassist.tools.HotSwapper`.

## 4. Introspection and customization
`CtClass` provides methods for introspection. The introspective ability of Javassist is compatible with that of the Java reflection API. `CtClass` provides `getName()`, `getSuperclass()`, `getMethods()`, and so on. `CtClass` also provides methods for modifying a class definition. It allows to add a new field, constructor, and method. Instrumenting a method body is also possible.

### 4.1 Inserting source text at the beginning/end of a method body
The `String` object passed to the methods `insertBefore()`, `insertAfter()`, `addCatch()`, and `insertAt()` are compiled by the compiler included in Javassist. Since the compiler supports language extensions, several identifiers starting with `$` have special meaning:

identifiers | meaning
---|-----
`$0, $1, $2, ...` | `this` and actual parameters
`$args` | An array of parameters. The type of `$args` is `Object[]`.
`$$` | All actual parameters. For example, `m($$)` is equivalent to `m($1,$2,...)`
`$cflow(...)` | `cflow` variable
`$r` | The result type. It is used in a cast expression.
`$w` | The wrapper type. It is used in a cast expression.
`$_` | The resulting value
`$sig` | An array of `java.lang.Class` objects representing the formal parameter types.
`$type` | A `java.lang.Class` object representing the formal result type.
`$class` | A `java.lang.Class` object representing the class currently edited.

#### $0, $1, $2, ...
`$1` represents the first parameter, `$2` represents the second parameter, and so on.

`$0` is equivalent to `this`. If the method is static, `$0` is not available.

```
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
CtMethod m = cc.getDeclaredMethod("move");
m.insertBefore("{ System.out.println($1); System.out.println($2); }");
cc.writeFile();
```

#### $$
If `move()` does not take any parameters, then `move($$)` is equivalent to `move()`.

`$$` can be used with another method. If you write an expression:
```
exMove($$, context)
```
then this expression is equivalent to:
```
exMove($1, $2, $3, context)
```

#### $cflow
To use `$cflow`, first declare that `$cflow` is used for monitoring calls to the method `fact()`:
```
CtMethod cm = ...;
cm.useCflow("fact");
```
Then, `$cflow(fact)` represents the depth of the recursive calls to the method specified by `cm`. The value of `$cflow(fact)` is 0 (zero) when the method is first called whereas it is 1 when the method is recursively called within the method. For example,
```
cm.insertBefore("if ($cflow(fact) == 0)"
	+ "    System.out.println(\"fact \" + $1);");
```

#### $r
`$r` represents the result type (return type) of the method.
- If the result type is `int`, then `($r)` converts from `java.lang.Integer` to `int`
- If the result type is `void`, then `($r)` does not convert a type
- Even if the result type is `void`, the following `return` statement is valid: `return ($r)result;`. This `return` statement is regarded as the equivalent of the `return` statement without a resulting value: `return;`

#### $w
If the type of the expression following `($w)` is not a primitive type, then `($w)` does nothing.

#### $_
The variable `$_` represents the resulting value of the method. The type of that variable is the type of the result type (the return type) of the method. If the result type is `void`, then the type of `$_` is `Object` and the value of `$_` is `null`.

Note that the value of `$_` is never thrown to the caller; it is rather discarded.

#### addCatch()
`addCatch()` inserts a code fragment into a method body so that the code fragment is executed when the method body throws an exception and the control returns to the caller. In the source text representing the inserted code fragment, the exception value is referred to with the special variable `$e`.
```
CtClass etype = ClassPool.getDefault().get("java.io.IOException");
m.addCatch("{ System.out.println($e); throw $e; }", etype);
```
Note that the inserted code fragment must end with a `throw` or `return` statement.

### 4.2 Altering a method body
`CtMethod` and `CtConstructor` provide `setBody()` for substituting a whole method body. They compile the given source text into Java bytecode and substitutes it for the original method body. If the given source text is `null`, the substituted body includes only a `return` statement, which returns zero or null unless the result type is `void`.

Note that `$_` is not available.

#### Substituting source text for an existing expression
Javassist allows modifying only an expression included in a method body. `javassist.expr.ExprEditor` is a class for replacing an expression in a method body. The users can define a subclass of `ExprEditor` to specify how an expression is modified.
```
CtMethod cm = ... ;
cm.instrument(
    new ExprEditor() {
        public void edit(MethodCall m)
                      throws CannotCompileException
        {
            if (m.getClassName().equals("Point")
                          && m.getMethodName().equals("move"))
                m.replace("{ $1 = 0; $_ = $proceed($$); }");
        }
    });
```
Note that the substituted code is not an expression but a statement or a block. It cannot be or contain a try-catch statement.

If the given block is an empty block, that is, if `replace("{}")` is executed, then the expression is removed from the method body. If you want to insert a statement (or a block) before/after the expression, a block like the following should be passed to `replace()`:
```
{ before-statements;
  $_ = $proceed($$);
  after-statements; }
```

#### javassist.expr.MethodCall
A `MethodCall` object represents a method call. 
- The method `replace()` in `MethodCall` substitutes a statement or a block for the method call. It receives source text representing the substitued statement or block, in which the identifiers starting with `$` have special meaning as in the source text passed to `insertBefore()`.

#### javassist.expr.ConstructorCall
A `ConstructorCall` object represents a constructor call such as `this()` and `super` included in a constructor body.
- The method `replace()` in `ConstructorCall` substitutes a statement or a block for the constructor call. It receives source text representing the substituted statement or block, in which the identifiers starting with `$` have special meaning as in the source text passed to `insertBefore()`.

#### javassist.expr.FieldAccess
A `FieldAccess` object represents field access.
- The method `edit()` in `ExprEditor` receives this object if field access is found.
- The method `replace()` in `FieldAccess` receives source text representing the substitued statement or block for the field access.

#### javassist.expr.NewExpr
A `NewExpr` object represents object creation with the `new` operator (not including array creation).
- The method `edit()` in `ExprEditor` receives this object if object creation is found.
- The method `replace()` in `NewExpr` receives source text representing the substitued statement or block for the object creation.

#### javassist.expr.NewArray
A `NewArray` object represents array creation with the `new` operator.
- The method `edit()` in `ExprEditor` receives this object if array creation is found.
- The method `replace()` in `NewArray` receives source text representing the substitued statement or block for the array creation.

#### javassist.expr.Instanceof
A `Instanceof` object represents an `instanceof` expression.
- The method `edit()` in `ExprEditor` receives this object if an instanceof expression is found.
- The method `replace()` in `Instanceof` receives source text representing the substitued statement or block for the expression.

#### javassist.expr.Cast
A `Cast` object represents an expression for explicit type casting.
- The method `edit()` in `ExprEditor` receives this object if explicit type casting is found.
- The method `replace()` in `Cast` receives source text representing the substitued statement or block for the expression.

#### javassist.expr.Handler
A `Handler` object represents a `catch` clause of `try-catch` statement.
- The method `edit()` in `ExprEditor` receives this object if a `catch` is found.
- The method `insertBefore()` in `Handler` compiles the received source text and inserts it at the beginning of the `catch` clause.

### 4.3 Adding a new method or field
#### Adding a method
Javassist allows the users to create a new method and constructor from scratch. `CtNewMethod` and `CtNewConstructor` provide several factory methods, which are static methods for creating `CtMethod` or `CtConstructor` objects. Especially, `make()` creates a `CtMethod` or `CtConstructor` object from the given source text.
```
CtClass point = ClassPool.getDefault().get("Point");
CtMethod m = CtNewMethod.make(
                 "public int xmove(int dx) { x += dx; }",
                 point);
point.addMethod(m);
```
```
CtClass point = ClassPool.getDefault().get("Point");
CtMethod m = CtNewMethod.make(
                 "public int ymove(int dy) { $proceed(0, dy); }",
                 point, "this", "move");
```
```
CtClass cc = ... ;
CtMethod m = new CtMethod(CtClass.intType, "move",
                          new CtClass[] { CtClass.intType }, cc);
cc.addMethod(m);
m.setBody("{ x += $1; }");
cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);
```
Since Javassist makes a class abstract if an abstract method is added to the class, you have to explicitly change the class back to a non-abstract one after calling `setBody()`.

#### Mutual recursive methods
Javassist cannot compile a method if it calls another method that has not been added to a class. (Javassist can compile a method that calls itself recursively.) To add mutual recursive methods to a class, you need a trick shown below. Suppose that you want to add methods `m()` and `n()` to a class represented by `cc`:
```
CtClass cc = ... ;
CtMethod m = CtNewMethod.make("public abstract int m(int i);", cc);
CtMethod n = CtNewMethod.make("public abstract int n(int i);", cc);
cc.addMethod(m);
cc.addMethod(n);
m.setBody("{ return ($1 <= 0) ? 1 : (n($1 - 1) * $1); }");
n.setBody("{ return m($1); }");
cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);
```

- You must first make two abstract methods and add them to the class.
- Then you can give the method bodies to these methods even if the method bodies include method calls to each other.
- Finally you must change the class to a not-abstract class since `addMethod()` automatically changes a class into an abstract one if an abstract method is added.

#### Adding a field
Javassist also allows the users to create a new field.
```
CtClass point = ClassPool.getDefault().get("Point");
CtField f = new CtField(CtClass.intType, "z", point);
// point.addField(f);
point.addField(f, "0"); // initial value is 0
```
```
CtClass point = ClassPool.getDefault().get("Point");
CtField f = CtField.make("public int z = 0;", point);
point.addField(f);
```

#### Removing a member
To remove a field or a method, call `removeField()` or `removeMethod()` in `CtClass`. A `CtConstructor` can be removed by `removeConstructor()` in `CtClass`.

### 4.4 Annotations
`CtClass`, `CtMethod`, `CtField` and `CtConstructor` provides a convenient method `getAnnotations()` for reading annotations. It returns an annotation-type object.
```
public @interface Author {
    String name();
    int year();
}
```

To use `getAnnotations()`, annotation types such as `Author` must be included in the current class path. **They must be also accessible from a `ClassPool` object.** If the class file of an annotation type is not found, Javassist cannot obtain the default values of the members of that annotation type.

### 4.5 Runtime support classes
In most cases, a class modified by Javassist does not require Javassist to run. However, some kinds of bytecode generated by the Javassist compiler need runtime support classes, which are in the `javassist.runtime` package (for details, please read the API reference of that package). Note that the `javassist.runtime` package is the only package that classes modified by Javassist may need for running. The other Javassist classes are never used at runtime of the modified classes.

### 4.6 Import
All the class names in source code must be fully qualified (they must include package names). However, the `java.lang` package is an exception
```
ClassPool pool = ClassPool.getDefault();
pool.importPackage("java.awt");
CtClass cc = pool.makeClass("Test");
CtField f = CtField.make("public Point p;", cc);
cc.addField(f);
```

Note that `importPackage()` **does not** affect the `get()` method in `ClassPool`. Only the compiler considers the imported packages. The parameter to `get()` must be always a fully qualified name.

### 4.7 Limitations
In the current implementation, the Java compiler included in Javassist has several limitations with respect to the language that the compiler can accept. Those limitations are:
- The new syntax introduced by J2SE 5.0 (including enums and generics) has not been supported. Annotations are supported by the low level API of Javassist. See the `javassist.bytecode.annotation` package (and also `getAnnotations()` in `CtClass` and `CtBehavior`). Generics are also only partly supported.
- Array initializers, a comma-separated list of expressions enclosed by braces `{` and `}`, are not available unless the array dimension is one.
- Inner classes or anonymous classes are not supported. Note that this is a limitation of the compiler only. It cannot compile source code including an anonymous-class declaration. Javassist can read and modify a class file of inner/anonymous class.
- Labeled `continue` and `break` statements are not supported.
- The compiler does not correctly implement the Java method dispatch algorithm. The compiler may confuse if methods defined in a class have the same name but take different parameter lists.
- The users are recommended to use `#` as the separator between a class name and a static method or field name.

## 5. Bytecode level API
Javassist also provides lower-level API for directly editing a class file.

If you want to just produce a simple class file, `javassist.bytecode.ClassFileWriter` might provide the best API for you. It is much faster than `javassist.bytecode.ClassFile` although its API is minimum.

### 5.1 Obtaining a ClassFile object
```
BufferedInputStream fin = new BufferedInputStream(new FileInputStream("Point.class"));
ClassFile cf = new ClassFile(new DataInputStream(fin));
```
You can create a new class file from scratch.
```
ClassFile cf = new ClassFile(false, "test.Foo", null);
cf.setInterfaces(new String[] { "java.lang.Cloneable" });
FieldInfo f = new FieldInfo(cf.getConstPool(), "width", "I");
f.setAccessFlags(AccessFlag.PUBLIC);
cf.addField(f);
cf.write(new DataOutputStream(new FileOutputStream("Foo.class")));
```

### 5.2 Adding and removing a member
`ClassFile` provides `addField()` and `addMethod()` for adding a field or a method (note that a constructor is regarded as a method at the bytecode level). It also provides `addAttribute()` for adding an attribute to the class file.

Note that `FieldInfo`, `MethodInfo`, and `AttributeInfo` objects include a link to a `ConstPool` (constant pool table) object. The `ConstPool` object must be common to the `ClassFile` object and a `FieldInfo` (or `MethodInfo` etc.) object that is added to that `ClassFile` object. In other words, a `FieldInfo` (or `MethodInfo` etc.) object must not be shared among different `ClassFile` objects.

To remove a field or a method from a `ClassFile` object, you must first obtain a `java.util.List` object containing all the fields of the class. `getFields()` and `getMethods()` return the lists. A field or a method can be removed by calling `remove()` on the `List` object. An attribute can be removed in a similar way. Call `getAttributes()` in `FieldInfo` or `MethodInfo` to obtain the list of attributes, and remove one from the list.

### 5.3 Traversing a method body
To examine every bytecode instruction in a method body, `CodeIterator` is useful.
```
ClassFile cf = ... ;
MethodInfo minfo = cf.getMethod("move");    // we assume move is not overloaded.
CodeAttribute ca = minfo.getCodeAttribute();
CodeIterator ci = ca.iterator();
while (ci.hasNext()) {
    int index = ci.next();
    int op = ci.byteAt(index);
    System.out.println(Mnemonic.OPCODE[op]);
}
```

A `CodeIterator` object allows you to visit every bytecode instruction one by one from the beginning to the end. The following methods are part of the methods declared in `CodeIterator`:
- `void begin()`: Move to the first instruction.
- `void move(int index)`: Move to the instruction specified by the given index.
- `boolean hasNext()`: Returns true if there is more instructions.
- `int next()`: Returns the index of the next instruction. **Note that it does not return the opcode of the next instruction.**
- `int byteAt(int index)`: Returns the unsigned 8bit value at the index.
- `int u16bitAt(int index)`: Returns the unsigned 16bit value at the index.
- `int write(byte[] code, int index)`: Writes a byte array at the index.
- `void insert(int index, byte[] code)`: Inserts a byte array at the index. Branch offsets etc. are automatically adjusted.

### 5.4 Producing a bytecode sequence
A `Bytecode` object represents a sequence of bytecode instructions. It is a growable array of bytecode.
```
ConstPool cp = ...;    // constant pool table
Bytecode b = new Bytecode(cp, 1, 0);
b.addIconst(3);
b.addReturn(CtClass.intType);
CodeAttribute ca = b.toCodeAttribute();
```

`Bytecode` can be used to construct a method.
```
ClassFile cf = ...
Bytecode code = new Bytecode(cf.getConstPool());
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
code.setMaxLocals(1);
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
```

### 5.5 Annotations (Meta tags)
Annotations are stored in a class file as runtime invisible (or visible) annotations attribute. These attributes can be obtained from `ClassFile`, `MethodInfo`, or `FieldInfo` objects. Call `getAttribute(AnnotationsAttribute.invisibleTag)` on those objects. For more details, see the javadoc manual of `javassist.bytecode.AnnotationsAttribute` class and the `javassist.bytecode.annotation` package.

Javassist also let you access annotations by the higher-level API. If you want to access annotations through `CtClass`, call `getAnnotations()` in `CtClass` or `CtBehavior`.

## 6. Generics
The lower-level API of Javassist fully supports generics introduced by Java 5. On the other hand, the higher-level API such as `CtClass` does not directly support generics. However, this is not a serious problem for bytecode transformation.

The generics of Java is implemented by the erasure technique. After compilation, all type parameters are dropped off.

Note that no type parameters are necessary. Since `get` returns an `Object`, an explicit type cast is needed at the caller site if the source code is compiled by Javassist. For example, if the type parameter `T` is `String`, then (`String`) must be inserted as follows:
```
Wrapper w = ...
String s = (String)w.get();
```

## 7. Varargs
Currently, Javassist does not directly support varargs. So to make a method with varargs, you must explicitly set a method modifier.
```
CtClass cc = /* target class */;
CtMethod m = CtMethod.make("public int length(int[] args) { return args.length; }", cc);
m.setModifiers(m.getModifiers() | Modifier.VARARGS);
cc.addMethod(m);
```

## 8. J2ME
If you modify a class file for the J2ME execution environment, you must perform preverification. Preverifying is basically producing stack maps, which is similar to stack map tables introduced into J2SE at JDK 1.6. Javassist maintains the stack maps for J2ME only if `javassist.bytecode.MethodInfo.doPreverify` is true.

You can also manually produce a stack map for a modified method. For a given method represented by a `CtMethod` object `m`, you can produce a stack map by calling the following methods:
```
m.getMethodInfo().rebuildStackMapForME(cpool);
```
Here, `cpool` is a `ClassPool` object, which is available by calling `getClassPool()` on a `CtClass` object. A `ClassPool` object is responsible for finding class files from given class pathes. To obtain all the `CtMethod` objects, call the `getDeclaredMethods` method on a `CtClass` object.

## 9. Boxing/Unboxing
Boxing and unboxing in Java are syntactic sugar. There is no bytecode for boxing or unboxing. So the compiler of Javassist does not support them.

For Javassist, however, you must explicitly convert a value type from `int` to `Integer`:
```
Integer i = new Integer(3);
```

## 10. Debug
Set `CtClass.debugDump` to a directory name. Then all class files modified and generated by Javassist are saved in that directory. To stop this, set `CtClass.debugDump` to null. The default value is null.
```
CtClass.debugDump = "./dump";
```
All modified class files are saved in `./dump`.

## Results
- `ReadWriteBytecodeTest`
- `ClassPoolTest`
- `ClassLoaderTest`
- `IntrospectionAndCustomizationTest`
- `BytecodeLevelApiTest`

### What Is the Bytecode?
```
cd java-repositories/jdk8/t5750/javassist/domain
javap -c Pair.class
```
```
public class t5750.javassist.domain.Pair extends java.awt.geom.Point2D implements java.io.Serializable {
  public t5750.javassist.domain.Pair(int, int);
    Code:
       0: aload_0
       1: invokespecial #80                 // Method java/awt/geom/Point2D."<init>":()V
       4: aload_0
       5: iload_1
       6: putfield      #75                 // Field x:I
       9: aload_0
      10: iload_2
      11: putfield      #76                 // Field y:I
      14: return

  public void move(int, int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #75                 // Field x:I
       5: aload_0
       6: iload_2
       7: putfield      #76                 // Field y:I
      10: return
}
```
Let's analyze the bytecode instructions of the `move()` method:
- `aload_0` instruction is loading a reference onto the stack from the local variable 0
- `iload_1` is loading an int value from the local variable 1
- `putfield` is setting a field `x` of our object. All operations are analogical for field `y`
- The last instruction is a `return`

## References
- [Getting Started with Javassist](http://www.javassist.org/tutorial/tutorial.html)
- [Dynamic Class Loading Example](https://examples.javacodegeeks.com/core-java/dynamic-class-loading-example/)
- [Introduction to Javassist](https://www.baeldung.com/javassist)