proxygenerator.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 1,689 行 · 第 1/4 页

JAVA
1,689
字号
/* * @(#)ProxyGenerator.java	1.12 06/10/10 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved.   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER   *    * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public License version   * 2 only, as published by the Free Software Foundation.    *    * This program is distributed in the hope that it will be useful, but   * WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * General Public License version 2 for more details (a copy is   * included at /legal/license.txt).    *    * You should have received a copy of the GNU General Public License   * version 2 along with this work; if not, write to the Free Software   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   * 02110-1301 USA    *    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa   * Clara, CA 95054 or visit www.sun.com if you need additional   * information or have any questions.  * */package sun.misc;import java.lang.reflect.*;import java.io.*;import java.util.*;import sun.tools.java.RuntimeConstants;import sun.security.action.GetBooleanAction;/** * ProxyGenerator contains the code to generate a dynamic proxy class * for the java.lang.reflect.Proxy API. * * The external interfaces to ProxyGenerator is the static * "generateProxyClass" method. * * @author	Peter Jones * @version	1.3, 00/02/02 * @since	JDK1.3 */public class ProxyGenerator {    /*     * In the comments below, "JVMS" refers to The Java Virtual Machine     * Specification Second Edition and "JLS" refers to the original     * version of The Java Language Specification, unless otherwise     * specified.     */    /*     * Note that this class imports sun.tools.java.RuntimeConstants and     * references many final static primitive fields of that interface.     * By JLS section 13.4.8, the compiler should inline all of these     * references, so their presence should not require the loading of     * RuntimeConstants at runtime when ProxyGenerator is linked.  This     * non-requirement is important because ProxyGenerator is intended     * to be bundled with the JRE, but classes in the sun.tools     * hierarchy, such as RuntimeConstants, are not.     *     * The Java compiler does add a CONSTANT_Class entry in the constant     * pool of this class for "sun/tools/java/RuntimeConstants".  The     * evaluation of bugid 4162387 seems to imply that this is for the     * compiler's implementation of the "-Xdepend" option.  This     * CONSTANT_Class entry may, however, confuse tools which use such     * entries to compute runtime class dependencies or virtual machine     * implementations which use them to effect eager class resolution.     */    /** name of the superclass of proxy classes */    private final static String superclassName = "java/lang/reflect/Proxy";    /** name of field for storing a proxy instance's invocation handler */    private final static String handlerFieldName = "h";    /** debugging flag for saving generated class files */    private final static boolean saveGeneratedFiles =	((Boolean) java.security.AccessController.doPrivileged(	    new GetBooleanAction(		"sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();    /**     * Generate a proxy class given a name and a list of proxy interfaces.     */    public static byte[] generateProxyClass(final String name,					    Class[] interfaces)    {	ProxyGenerator gen = new ProxyGenerator(name, interfaces);	final byte[] classFile = gen.generateClassFile();	if (saveGeneratedFiles) {	    java.security.AccessController.doPrivileged(	    new java.security.PrivilegedAction() {		public Object run() {		    try {			FileOutputStream file =			    new FileOutputStream(dotToSlash(name) + ".class");			file.write(classFile);			file.close();			return null;		    } catch (IOException e) {			throw new InternalError(			    "I/O exception saving generated file: " + e);		    }		}	    });	}	return classFile;    }    /* preloaded Method objects for methods in java.lang.Object */    private static Method hashCodeMethod;    private static Method equalsMethod;    private static Method toStringMethod;    static {	try {	    hashCodeMethod = Object.class.getMethod("hashCode", null);	    equalsMethod =		Object.class.getMethod("equals", new Class[] { Object.class });	    toStringMethod = Object.class.getMethod("toString", null);        } catch (NoSuchMethodException e) {	    throw new NoSuchMethodError(e.getMessage());	}    }    /** name of proxy class */    private String className;    /** proxy interfaces */     private Class[] interfaces;    /** constant pool of class being generated */    private ConstantPool cp = new ConstantPool();    /** FieldInfo struct for each field of generated class */    private List fields = new ArrayList();    /** MethodInfo struct for each method of generated class */    private List methods = new ArrayList();    /**     * for each method to be proxied, maps method name and parameter     * descriptor to ProxyMethod object     */    private Map proxyMethods = new HashMap(11);    /**     * Construct a ProxyGenerator to generate a proxy class with the     * specified name and for the given interfaces.     *     * A ProxyGenerator object contains the state for the ongoing     * generation of a particular proxy class.     */    private ProxyGenerator(String className, Class[] interfaces) {	this.className = className;	this.interfaces = interfaces;    }    /**     * Generate a class file for the proxy class.  This method drives the     * class file generation process.     */    private byte[] generateClassFile() {	/* ============================================================	 * Step 1: Assemble ProxyMethod objects for all methods to	 * generate proxy dispatching code for.	 */	/*	 * Record that proxy methods are needed for the hashCode, equals,	 * and toString methods of java.lang.Object.  This is done before	 * the methods from the proxy interfaces so that the methods from	 * java.lang.Object take precedence over duplicate methods in the	 * proxy interfaces.	 */	addProxyMethod(hashCodeMethod, Object.class);	addProxyMethod(equalsMethod, Object.class);	addProxyMethod(toStringMethod, Object.class);	/*	 * Now record all of the methods from the proxy interfaces, giving	 * earlier interfaces precedence over later ones with duplicate	 * methods.	 */	for (int i = 0; i < interfaces.length; i++) {	    Method[] methods = interfaces[i].getMethods();	    for (int j = 0; j < methods.length; j++) {		addProxyMethod(methods[j], interfaces[i]);	    }	}	/* ============================================================	 * Step 2: Assemble FieldInfo and MethodInfo structs for all of	 * fields and methods in the class we are generating.	 */	try {//	    fields.add(new FieldInfo(//		handlerFieldName, "Ljava/lang/reflect/InvocationHandler;",//		RuntimeConstants.ACC_PRIVATE | RuntimeConstants.ACC_FINAL));	    methods.add(generateConstructor());	    for (Iterator iter = proxyMethods.values().iterator();		 iter.hasNext();)	    {		ProxyMethod pm = (ProxyMethod) iter.next();		// add static field for method's Method object		fields.add(new FieldInfo(pm.methodFieldName,		    "Ljava/lang/reflect/Method;",		    RuntimeConstants.ACC_PRIVATE |			RuntimeConstants.ACC_STATIC));		// generate code for proxy method and add it		methods.add(pm.generateMethod());	    }	    methods.add(generateStaticInitializer());	} catch (IOException e) {	    throw new InternalError("unexpected I/O Exception");	}	/* ============================================================	 * Step 3: Write the final class file.	 */	/*	 * Make sure that constant pool indexes are reserved for the	 * following items before starting to write the final class file.	 */	cp.getClass(dotToSlash(className));	cp.getClass(superclassName);	for (int i = 0; i < interfaces.length; i++) {	    cp.getClass(dotToSlash(interfaces[i].getName()));	}	/*	 * Disallow new constant pool additions beyond this point, since	 * we are about to write the final constant pool table.	 */	cp.setReadOnly();	ByteArrayOutputStream bout = new ByteArrayOutputStream();	DataOutputStream dout = new DataOutputStream(bout);	try {	    /*	     * Write all the items of the "ClassFile" structure.	     * See JVMS section 4.1.	     */					// u4 magic;	    dout.writeInt(RuntimeConstants.JAVA_MAGIC);					// u2 major_version;	    dout.writeShort(RuntimeConstants.JAVA_DEFAULT_MINOR_VERSION);					// u2 minor_version;	    dout.writeShort(RuntimeConstants.JAVA_DEFAULT_VERSION);	    cp.write(dout);		// (write constant pool)					// u2 access_flags;	    dout.writeShort(RuntimeConstants.ACC_PUBLIC |			    RuntimeConstants.ACC_FINAL |			    RuntimeConstants.ACC_SUPER);					// u2 this_class;	    dout.writeShort(cp.getClass(dotToSlash(className)));					// u2 super_class;	    dout.writeShort(cp.getClass(superclassName));					// u2 interfaces_count;	    dout.writeShort(interfaces.length);					// u2 interfaces[interfaces_count];	    for (int i = 0; i < interfaces.length; i++) {		dout.writeShort(cp.getClass(		    dotToSlash(interfaces[i].getName())));	    }					// u2 fields_count;	    dout.writeShort(fields.size());					// field_info fields[fields_count];	    for (Iterator iter = fields.iterator(); iter.hasNext();) {		FieldInfo f = (FieldInfo) iter.next();		f.write(dout);	    }					// u2 methods_count;	    dout.writeShort(methods.size());					// method_info methods[methods_count];	    for (Iterator iter = methods.iterator(); iter.hasNext();) {		MethodInfo m = (MethodInfo) iter.next();		m.write(dout);	    }	   				 // u2 attributes_count;	    dout.writeShort(0);	// (no ClassFile attributes for proxy classes)	} catch (IOException e) {	    throw new InternalError("unexpected I/O Exception");	}	return bout.toByteArray();    }    /**     * Add another method to be proxied, either by creating a new ProxyMethod     * object or augmenting an old one for a duplicate method.     *     * "fromClass" indicates the proxy interface that the method was found     * through, which may be different from (a subinterface of) the method's     * "declaring class".  Note that the first Method object passed for a     * given name and parameter types identifies the Method object (and thus     * the declaring class) that will be passed to the invocation handler's     * "invoke" method for a given set of duplicate methods.     */    private void addProxyMethod(Method m, Class fromClass) {	String name = m.getName();	Class[] parameterTypes = m.getParameterTypes();	Class returnType = m.getReturnType();	Class[] exceptionTypes = m.getExceptionTypes();	String key = name + getParameterDescriptors(parameterTypes);	ProxyMethod pm = (ProxyMethod) proxyMethods.get(key);	if (pm != null) {	    /*	     * If a proxy method with the same name and parameter types has	     * already been added, verify that it has the same return type...	     */	    if (returnType != pm.returnType) {		throw new IllegalArgumentException(		    "methods with same name and parameter " +		    "signature but different return type in " +		    pm.fromClass + " and " + fromClass +		    ": " + key);	    }	    /*	     * ...and compute the greatest common set of exceptions that can	     * thrown by the proxy method compatibly with both inherited	     * methods.	     */	    List legalExceptions = new ArrayList();	    collectCompatibleTypes(		exceptionTypes, pm.exceptionTypes, legalExceptions);	    collectCompatibleTypes(		pm.exceptionTypes, exceptionTypes, legalExceptions);	    pm.exceptionTypes = new Class[legalExceptions.size()];	    pm.exceptionTypes =		(Class[]) legalExceptions.toArray(pm.exceptionTypes);	} else {	    pm = new ProxyMethod(name, parameterTypes, returnType,		exceptionTypes, fromClass, "m" + proxyMethods.size());	    proxyMethods.put(key, pm);	}    }    /**     * A FieldInfo object contains information about a particular field     * in the class being generated.  The class mirrors the data items of     * the "field_info" structure of the class file format (see JVMS 4.5).     */    private class FieldInfo {	public int accessFlags;	public String name;	public String descriptor;	public FieldInfo(String name, String descriptor, int accessFlags) {	    this.name = name;	    this.descriptor = descriptor;	    this.accessFlags = accessFlags;	    /*	     * Make sure that constant pool indexes are reserved for the	     * following items before starting to write the final class file.	     */	    cp.getUtf8(name);	    cp.getUtf8(descriptor);	}	public void write(DataOutputStream out) throws IOException {	    /*	     * Write all the items of the "field_info" structure.	     * See JVMS section 4.5.	     */					// u2 access_flags;	    out.writeShort(accessFlags);					// u2 name_index;	    out.writeShort(cp.getUtf8(name));					// u2 descriptor_index;	    out.writeShort(cp.getUtf8(descriptor));					// u2 attributes_count;	    out.writeShort(0);	// (no field_info attributes for proxy classes)	}    }    /**     * An ExceptionTableEntry object holds values for the data items of     * an entry in the "exception_table" item of the "Code" attribute of     * "method_info" structures (see JVMS 4.7.3).     */    private static class ExceptionTableEntry {	public short startPc;	public short endPc;	public short handlerPc;	public short catchType;	public ExceptionTableEntry(short startPc, short endPc,				   short handlerPc, short catchType)	{	    this.startPc = startPc;	    this.endPc = endPc;	    this.handlerPc = handlerPc;	    this.catchType = catchType;	}    };    /**     * A MethodInfo object contains information about a particular method

⌨️ 快捷键说明

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