概要
Unlike other similar bytecode editors, Javassist provides two levels of API: source level and bytecode level.
生成字节码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package me.zhongmingmao.javassist;
public class Point {
private int x; private int y;
public Point(int x, int y) { this.x = x; this.y = y; }
public void move(int x, int y) { this.x = x; this.y = y; } }
|
1 2
| $ javac me/zhongmingmao/javassist/Point.java $ javap -v me.zhongmingmao.javassist.Point
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| Classfile /xxx/me/zhongmingmao/javassist/Point.class Last modified Feb 10, 2022; size 352 bytes MD5 checksum a44e68a69467ce37199980dd9bc5d30a Compiled from "Point.java" public class me.zhongmingmao.javassist.Point minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#16 #2 = Fieldref #4.#17 #3 = Fieldref #4.#18 #4 = Class #19 #5 = Class #20 #6 = Utf8 x #7 = Utf8 I #8 = Utf8 y #9 = Utf8 <init> #10 = Utf8 (II)V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 move #14 = Utf8 SourceFile #15 = Utf8 Point.java #16 = NameAndType #9:#21 #17 = NameAndType #6:#7 #18 = NameAndType #8:#7 #19 = Utf8 me/zhongmingmao/javassist/Point #20 = Utf8 java/lang/Object #21 = Utf8 ()V { public me.zhongmingmao.javassist.Point(int, int); descriptor: (II)V flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: aload_0 1: invokespecial #1 4: aload_0 5: iload_1 6: putfield #2 9: aload_0 10: iload_2 11: putfield #3 14: return LineNumberTable: line 8: 0 line 9: 4 line 10: 9 line 11: 14
public void move(int, int); descriptor: (II)V flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: aload_0 1: iload_1 2: putfield #2 5: aload_0 6: iload_2 7: putfield #3 10: return LineNumberTable: line 14: 0 line 15: 5 line 16: 10 } SourceFile: "Point.java"
|
Javassist
生成新类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private static void generateClass() throws CannotCompileException { ClassFile classFile = new ClassFile(false, "me.zhongmingmao.javassist.JavassistGeneratedClass", null); classFile.setInterfaces(new String[] {"java.lang.Cloneable"}); FieldInfo fieldInfo = new FieldInfo(classFile.getConstPool(), "id", "I"); fieldInfo.setAccessFlags(AccessFlag.PUBLIC); classFile.addField(fieldInfo);
Class<?> klass = ClassPool.getDefault().makeClass(classFile).toClass(); assertTrue( Stream.of(klass.getInterfaces()) .map(Class::getCanonicalName) .anyMatch(interfaceName -> interfaceName.contentEquals("java.lang.Cloneable"))); assertTrue( Stream.of(klass.getFields()).map(Field::getName).anyMatch(field -> field.contains("id"))); }
|
读取字节码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private static void loadBytecode() throws BadBytecode, NotFoundException { CodeIterator iterator = ClassPool.getDefault() .get("me.zhongmingmao.javassist.Point") .getClassFile() .getMethod("move") .getCodeAttribute() .iterator();
List<String> ops = Lists.newArrayList(); while (iterator.hasNext()) { int index = iterator.next(); String op = Mnemonic.OPCODE[iterator.byteAt(index)]; System.out.println(index + " : " + op); ops.add(op); }
assertEquals( Arrays.asList("aload_0", "iload_1", "putfield", "aload_0", "iload_2", "putfield", "return"), ops); }
|
添加字段
1 2 3 4 5 6 7 8 9 10 11 12
| private void addField() throws NotFoundException, CannotCompileException { ClassFile classFile = ClassPool.getDefault().get("me.zhongmingmao.javassist.Point").getClassFile(); FieldInfo fieldInfo = new FieldInfo(classFile.getConstPool(), "id", "I"); fieldInfo.setAccessFlags(AccessFlag.PUBLIC); classFile.addField(fieldInfo);
assertTrue( Stream.of(ClassPool.getDefault().makeClass(classFile).toClass().getFields()) .map(Field::getName) .anyMatch(field -> field.contains("id"))); }
|
添加构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| private void addConstructor() throws NotFoundException, DuplicateMemberException, BadBytecode { ClassFile classFile = ClassPool.getDefault().get("me.zhongmingmao.javassist.Point").getClassFile();
MethodInfo methodInfo = new MethodInfo(classFile.getConstPool(), MethodInfo.nameInit, "()V"); Bytecode bytecode = new Bytecode(classFile.getConstPool()); bytecode.addAload(0); bytecode.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V"); bytecode.addReturn(null); CodeAttribute code = bytecode.toCodeAttribute(); methodInfo.setCodeAttribute(code); classFile.addMethod(methodInfo);
CodeIterator iterator = bytecode.toCodeAttribute().iterator(); List<String> ops = new LinkedList<>(); while (iterator.hasNext()) { int index = iterator.next(); String op = Mnemonic.OPCODE[iterator.byteAt(index)]; System.out.println(index + " : " + op); ops.add(op); }
assertEquals(Arrays.asList("aload_0", "invokespecial", "return"), ops); }
|