⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fieldtransformer.java

📁 好东西,hibernate-3.2.0,他是一开元的树杖hibernate-3.2.0
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
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.HashMap;
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;
import org.hibernate.bytecode.javassist.FieldFilter;
import org.hibernate.bytecode.javassist.FieldHandled;
import org.hibernate.bytecode.javassist.FieldHandler;

/**
 * The thing that handles actual class enhancement in regards to
 * intercepting field accesses.
 *
 * @author Muga Nishizawa
 */
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;

	private HashMap readableFields;

	private HashMap writableFields;

	public FieldTransformer() {
		this(null);
	}

	public FieldTransformer(FieldFilter f) {
		filter = f;
		readableFields = new HashMap();
		writableFields = new HashMap();
	}

	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);
					readableFields.put(finfo.getName(), finfo
							.getDescriptor());
				}
				if (filter.handleWrite(finfo.getDescriptor(), finfo
						.getName())) {
					addWriteMethod(classfile, finfo);
					writableFields.put(finfo.getName(), finfo
							.getDescriptor());
				}
			}
		}
	}

	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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -