📄 fieldtransformer.java
字号:
package org.hibernate.bytecode.javassist;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.util.Iterator;import java.util.List;import javassist.CannotCompileException;import javassist.bytecode.AccessFlag;import javassist.bytecode.BadBytecode;import javassist.bytecode.Bytecode;import javassist.bytecode.ClassFile;import javassist.bytecode.CodeAttribute;import javassist.bytecode.CodeIterator;import javassist.bytecode.ConstPool;import javassist.bytecode.Descriptor;import javassist.bytecode.FieldInfo;import javassist.bytecode.MethodInfo;import javassist.bytecode.Opcode;/** * The thing that handles actual class enhancement in regards to * intercepting field accesses. * * @author Muga Nishizawa * @author Steve Ebersole */public class FieldTransformer { private static final String EACH_READ_METHOD_PREFIX = "$javassist_read_"; private static final String EACH_WRITE_METHOD_PREFIX = "$javassist_write_"; private static final String FIELD_HANDLED_TYPE_NAME = FieldHandled.class .getName(); private static final String HANDLER_FIELD_NAME = "$JAVASSIST_READ_WRITE_HANDLER"; private static final String FIELD_HANDLER_TYPE_NAME = FieldHandler.class .getName(); private static final String HANDLER_FIELD_DESCRIPTOR = 'L' + FIELD_HANDLER_TYPE_NAME .replace('.', '/') + ';'; private static final String GETFIELDHANDLER_METHOD_NAME = "getFieldHandler"; private static final String SETFIELDHANDLER_METHOD_NAME = "setFieldHandler"; private static final String GETFIELDHANDLER_METHOD_DESCRIPTOR = "()" + HANDLER_FIELD_DESCRIPTOR; private static final String SETFIELDHANDLER_METHOD_DESCRIPTOR = "(" + HANDLER_FIELD_DESCRIPTOR + ")V"; private FieldFilter filter; public FieldTransformer() { this(null); } public FieldTransformer(FieldFilter f) { filter = f; } public void setFieldFilter(FieldFilter f) { filter = f; } public void transform(File file) throws Exception { DataInputStream in = new DataInputStream(new FileInputStream(file)); ClassFile classfile = new ClassFile(in); transform(classfile); DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); try { classfile.write(out); } finally { out.close(); } } public void transform(ClassFile classfile) throws Exception { if (classfile.isInterface()) { return; } try { addFieldHandlerField(classfile); addGetFieldHandlerMethod(classfile); addSetFieldHandlerMethod(classfile); addFieldHandledInterface(classfile); addReadWriteMethods(classfile); transformInvokevirtualsIntoPutAndGetfields(classfile); } catch (CannotCompileException e) { throw new RuntimeException(e.getMessage(), e); } } private void addFieldHandlerField(ClassFile classfile) throws CannotCompileException { ConstPool cp = classfile.getConstPool(); FieldInfo finfo = new FieldInfo(cp, HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.TRANSIENT); classfile.addField(finfo); } private void addGetFieldHandlerMethod(ClassFile classfile) throws CannotCompileException { ConstPool cp = classfile.getConstPool(); int this_class_index = cp.getThisClassInfo(); MethodInfo minfo = new MethodInfo(cp, GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR); /* local variable | this | */ Bytecode code = new Bytecode(cp, 2, 1); // aload_0 // load this code.addAload(0); // getfield // get field "$JAVASSIST_CALLBACK" defined already code.addOpcode(Opcode.GETFIELD); int field_index = cp.addFieldrefInfo(this_class_index, HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); code.addIndex(field_index); // areturn // return the value of the field code.addOpcode(Opcode.ARETURN); minfo.setCodeAttribute(code.toCodeAttribute()); minfo.setAccessFlags(AccessFlag.PUBLIC); classfile.addMethod(minfo); } private void addSetFieldHandlerMethod(ClassFile classfile) throws CannotCompileException { ConstPool cp = classfile.getConstPool(); int this_class_index = cp.getThisClassInfo(); MethodInfo minfo = new MethodInfo(cp, SETFIELDHANDLER_METHOD_NAME, SETFIELDHANDLER_METHOD_DESCRIPTOR); /* local variables | this | callback | */ Bytecode code = new Bytecode(cp, 3, 3); // aload_0 // load this code.addAload(0); // aload_1 // load callback code.addAload(1); // putfield // put field "$JAVASSIST_CALLBACK" defined already code.addOpcode(Opcode.PUTFIELD); int field_index = cp.addFieldrefInfo(this_class_index, HANDLER_FIELD_NAME, HANDLER_FIELD_DESCRIPTOR); code.addIndex(field_index); // return code.addOpcode(Opcode.RETURN); minfo.setCodeAttribute(code.toCodeAttribute()); minfo.setAccessFlags(AccessFlag.PUBLIC); classfile.addMethod(minfo); } private void addFieldHandledInterface(ClassFile classfile) { String[] interfaceNames = classfile.getInterfaces(); String[] newInterfaceNames = new String[interfaceNames.length + 1]; System.arraycopy(interfaceNames, 0, newInterfaceNames, 0, interfaceNames.length); newInterfaceNames[newInterfaceNames.length - 1] = FIELD_HANDLED_TYPE_NAME; classfile.setInterfaces(newInterfaceNames); } private void addReadWriteMethods(ClassFile classfile) throws CannotCompileException { List fields = classfile.getFields(); for (Iterator field_iter = fields.iterator(); field_iter.hasNext();) { FieldInfo finfo = (FieldInfo) field_iter.next(); if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0 && (!finfo.getName().equals(HANDLER_FIELD_NAME))) { // case of non-static field if (filter.handleRead(finfo.getDescriptor(), finfo .getName())) { addReadMethod(classfile, finfo); } if (filter.handleWrite(finfo.getDescriptor(), finfo .getName())) { addWriteMethod(classfile, finfo); } } } } private void addReadMethod(ClassFile classfile, FieldInfo finfo) throws CannotCompileException { ConstPool cp = classfile.getConstPool(); int this_class_index = cp.getThisClassInfo(); String desc = "()" + finfo.getDescriptor(); MethodInfo minfo = new MethodInfo(cp, EACH_READ_METHOD_PREFIX + finfo.getName(), desc); /* local variables | target obj | each oldvalue | */ Bytecode code = new Bytecode(cp, 5, 3); // aload_0 code.addAload(0); // getfield // get each field code.addOpcode(Opcode.GETFIELD); int base_field_index = cp.addFieldrefInfo(this_class_index, finfo .getName(), finfo.getDescriptor()); code.addIndex(base_field_index); // aload_0 code.addAload(0); // invokeinterface // invoke Enabled.getInterceptFieldCallback() int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME); code.addInvokeinterface(enabled_class_index, GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, 1); // ifnonnull code.addOpcode(Opcode.IFNONNULL); code.addIndex(4); // *return // each type addTypeDependDataReturn(code, finfo.getDescriptor()); // *store_1 // each type addTypeDependDataStore(code, finfo.getDescriptor(), 1); // aload_0 code.addAload(0); // invokeinterface // invoke Enabled.getInterceptFieldCallback() code.addInvokeinterface(enabled_class_index, GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, 1); // aload_0 code.addAload(0); // ldc // name of the field code.addLdc(finfo.getName()); // *load_1 // each type addTypeDependDataLoad(code, finfo.getDescriptor(), 1); // invokeinterface // invoke Callback.read*() // each type addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(), true); // *return // each type addTypeDependDataReturn(code, finfo.getDescriptor()); minfo.setCodeAttribute(code.toCodeAttribute()); minfo.setAccessFlags(AccessFlag.PUBLIC); classfile.addMethod(minfo); } private void addWriteMethod(ClassFile classfile, FieldInfo finfo) throws CannotCompileException { ConstPool cp = classfile.getConstPool(); int this_class_index = cp.getThisClassInfo(); String desc = "(" + finfo.getDescriptor() + ")V"; MethodInfo minfo = new MethodInfo(cp, EACH_WRITE_METHOD_PREFIX + finfo.getName(), desc); /* local variables | target obj | each oldvalue | */ Bytecode code = new Bytecode(cp, 6, 3); // aload_0 code.addAload(0); // invokeinterface // enabled.getInterceptFieldCallback() int enabled_class_index = cp.addClassInfo(FIELD_HANDLED_TYPE_NAME); code.addInvokeinterface(enabled_class_index, GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, 1); // ifnonnull (label1) code.addOpcode(Opcode.IFNONNULL); code.addIndex(9); // aload_0 code.addAload(0); // *load_1 addTypeDependDataLoad(code, finfo.getDescriptor(), 1); // putfield code.addOpcode(Opcode.PUTFIELD); int base_field_index = cp.addFieldrefInfo(this_class_index, finfo .getName(), finfo.getDescriptor()); code.addIndex(base_field_index); code.growStack(-Descriptor.dataSize(finfo.getDescriptor())); // return ; code.addOpcode(Opcode.RETURN); // aload_0 code.addAload(0); // dup code.addOpcode(Opcode.DUP); // invokeinterface // enabled.getInterceptFieldCallback() code.addInvokeinterface(enabled_class_index, GETFIELDHANDLER_METHOD_NAME, GETFIELDHANDLER_METHOD_DESCRIPTOR, 1); // aload_0 code.addAload(0); // ldc // field name code.addLdc(finfo.getName()); // aload_0 code.addAload(0); // getfield // old value of the field code.addOpcode(Opcode.GETFIELD); code.addIndex(base_field_index); code.growStack(Descriptor.dataSize(finfo.getDescriptor()) - 1); // *load_1 addTypeDependDataLoad(code, finfo.getDescriptor(), 1); // invokeinterface // callback.write*(..) addInvokeFieldHandlerMethod(classfile, code, finfo.getDescriptor(), false); // putfield // new value of the field
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -