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 + -
显示快捷键?