Đọc và Xuất Bytecode
ClassPool classPool = ClassPool.getDefault();
CtClass targetClass = classPool.get("example.Shape");
targetClass.setSuperclass(classPool.get("example.Point"));
targetClass.writeFile("d://output");
// byte[] bytes = targetClass.toBytecode();
// Class loadedClass = targetClass.toClass();
ClassPool quản lý việc tải lớp, hỗ trợ ba cách xuất bytecode.
Tạo Lớp Mới
ClassPool pool = ClassPool.getDefault();
CtClass newClass = pool.makeClass("Coordinate");
newClass.addMethod(method);
newClass.addField(field);
CtClass cung cấp API đơn giản để chỉnh sửa lớp.
Đóng Băng Lớp
Sau khi gọi writeFile(), toClass(), hoặc toBytecode(), CtClass bị đóng băng. Để tiếp tục chỉnh sửa:
CtClass cls = ...;
cls.writeFile();
cls.defrost();
cls.setSuperclass(...);
Khi ClassPool.doPruning=true, bộ nhớ sẽ được giải phóng khi lớp đóng băng.
Đường dẫn Tìm kiếm Lớp
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/custom/classpath");
ClassPath urlPath = new URLClassPath("example.org", 443, "/lib/", "com.example.");
pool.insertClassPath(urlPath);
byte[] classData = ...;
String className = "Demo";
pool.insertClassPath(new ByteArrayClassPath(className, classData));
InputStream input = ...;
CtClass ct = pool.makeClass(input);
Quản lý ClassPool
Giảm Tiêu thụ Bộ nhớ
CtClass instance = ...;
instance.writeFile();
instance.detach();
Hoặc tạo ClassPool riêng:
ClassPool customPool = new ClassPool(true);
customPool.appendClassPath("./lib");
ClassPool Phân cấp
ClassPool parent = ClassPool.getDefault();
ClassPool child = new ClassPool(parent);
child.insertClassPath("./modules");
Đổi Tên Lớp
ClassPool pool = ClassPool.getDefault();
CtClass original = pool.get("Vector");
original.setName("Matrix");
CtClass reloaded = pool.get("Vector");
Với lớp đã đóng băng:
CtClass frozen = pool.get("Array");
frozen.writeFile();
CtClass renamed = pool.getAndRename("Array", "Collection");
Quản lý Class Loader
ClassPool cp = ClassPool.getDefault();
CtClass hello = cp.get("Hello");
Class c = hello.toClass();
Tránh tải lại lớp đã load:
ClassPool cp = ClassPool.getDefault();
CtClass hello2 = cp.get("Hello2");
Class c2 = hello2.toClass(new CustomClassLoader());
Sử dụng Javassist Loader
ClassPool pool = ClassPool.getDefault();
Loader loader = new Loader(pool);
CtClass rectangle = pool.get("geometry.Rectangle");
rectangle.setSuperclass(pool.get("geometry.Point"));
Class cls = loader.loadClass("geometry.Rectangle");
Object obj = cls.newInstance();
Theo dõi Loader
public class CustomTranslator implements Translator {
public void start(ClassPool pool) {}
public void onLoad(ClassPool pool, String name) {
CtClass cc = pool.get(name);
cc.setModifiers(Modifier.PUBLIC);
}
}
Sửa đổi Hệ thống Lớp
ClassPool pool = ClassPool.getDefault();
CtClass stringClass = pool.get("java.lang.String");
CtField newField = new CtField(CtClass.intType, "hidden", stringClass);
newField.setModifiers(Modifier.PUBLIC);
stringClass.addField(newField);
stringClass.writeFile(".");
Chạy với: java -Xbootclasspath/p:. MainApp
Thao tác Phương thức
Chèn Mã vào Phương thức
CtMethod method = cc.getDeclaredMethod("move");
method.insertBefore("{ System.out.println($1); System.out.println($2); }");
Biến Đặc biệt trong Phương thức
- $0: this
- $1, $2: tham số
- $args: mảng tham số
- $_: giá trị trả về
- $r: kiểu trả về
Xử lý Ngoại lệ
CtMethod m = ...;
CtClass exType = ClassPool.getDefault().get("java.io.IOException");
m.addCatch("{ System.out.println($e); throw $e; }", exType);
Tạo Phương thức và Trường
CtClass point = ClassPool.getDefault().get("Point");
CtMethod newMethod = CtNewMethod.make(
"public int shiftX(int delta) { x += delta; return x; }", point);
point.addMethod(newMethod);
Tạo Trường
CtClass point = ClassPool.getDefault().get("Point");
CtField field = CtField.make("public int weight = 0;", point);
point.addField(field);
Ví dụ Hoàn chỉnh
package demo.javassist;
import javassist.*;
public class ClassCreator {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass userClass = pool.makeClass("model.User");
CtField idField = CtField.make("private int userId;", userClass);
CtField nameField = CtField.make("private String userName;", userClass);
userClass.addField(idField);
userClass.addField(nameField);
CtMethod getName = CtMethod.make("public String getUserName(){return userName;}", userClass);
CtMethod setName = CtMethod.make("public void setUserName(String name){userName = name;}", userClass);
userClass.addMethod(getName);
userClass.addMethod(setName);
CtConstructor paramCons = new CtConstructor(
new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, userClass);
paramCons.setBody("{this.userId = $1; this.userName = $2;}");
userClass.addConstructor(paramCons);
CtConstructor defaultCons = new CtConstructor(null, userClass);
defaultCons.setBody("{}");
userClass.addConstructor(defaultCons);
userClass.writeFile("./generated");
}
}