Source Code Cross Referenced for ProxyGenerator.java in  » 6.0-JDK-Modules » j2me » sun » misc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » sun.misc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * @(#)ProxyGenerator.java	1.12 06/10/10
0003:         *
0004:         * Copyright  1990-2006 Sun Microsystems, Inc. All Rights Reserved.  
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER  
0006:         *   
0007:         * This program is free software; you can redistribute it and/or  
0008:         * modify it under the terms of the GNU General Public License version  
0009:         * 2 only, as published by the Free Software Foundation.   
0010:         *   
0011:         * This program is distributed in the hope that it will be useful, but  
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of  
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  
0014:         * General Public License version 2 for more details (a copy is  
0015:         * included at /legal/license.txt).   
0016:         *   
0017:         * You should have received a copy of the GNU General Public License  
0018:         * version 2 along with this work; if not, write to the Free Software  
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  
0020:         * 02110-1301 USA   
0021:         *   
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa  
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional  
0024:         * information or have any questions. 
0025:         *
0026:         */
0027:
0028:        package sun.misc;
0029:
0030:        import java.lang.reflect.*;
0031:        import java.io.*;
0032:        import java.util.*;
0033:
0034:        import sun.tools.java.RuntimeConstants;
0035:        import sun.security.action.GetBooleanAction;
0036:
0037:        /**
0038:         * ProxyGenerator contains the code to generate a dynamic proxy class
0039:         * for the java.lang.reflect.Proxy API.
0040:         *
0041:         * The external interfaces to ProxyGenerator is the static
0042:         * "generateProxyClass" method.
0043:         *
0044:         * @author	Peter Jones
0045:         * @version	1.3, 00/02/02
0046:         * @since	JDK1.3
0047:         */
0048:        public class ProxyGenerator {
0049:            /*
0050:             * In the comments below, "JVMS" refers to The Java Virtual Machine
0051:             * Specification Second Edition and "JLS" refers to the original
0052:             * version of The Java Language Specification, unless otherwise
0053:             * specified.
0054:             */
0055:
0056:            /*
0057:             * Note that this class imports sun.tools.java.RuntimeConstants and
0058:             * references many final static primitive fields of that interface.
0059:             * By JLS section 13.4.8, the compiler should inline all of these
0060:             * references, so their presence should not require the loading of
0061:             * RuntimeConstants at runtime when ProxyGenerator is linked.  This
0062:             * non-requirement is important because ProxyGenerator is intended
0063:             * to be bundled with the JRE, but classes in the sun.tools
0064:             * hierarchy, such as RuntimeConstants, are not.
0065:             *
0066:             * The Java compiler does add a CONSTANT_Class entry in the constant
0067:             * pool of this class for "sun/tools/java/RuntimeConstants".  The
0068:             * evaluation of bugid 4162387 seems to imply that this is for the
0069:             * compiler's implementation of the "-Xdepend" option.  This
0070:             * CONSTANT_Class entry may, however, confuse tools which use such
0071:             * entries to compute runtime class dependencies or virtual machine
0072:             * implementations which use them to effect eager class resolution.
0073:             */
0074:
0075:            /** name of the superclass of proxy classes */
0076:            private final static String super className = "java/lang/reflect/Proxy";
0077:
0078:            /** name of field for storing a proxy instance's invocation handler */
0079:            private final static String handlerFieldName = "h";
0080:
0081:            /** debugging flag for saving generated class files */
0082:            private final static boolean saveGeneratedFiles = ((Boolean) java.security.AccessController
0083:                    .doPrivileged(new GetBooleanAction(
0084:                            "sun.misc.ProxyGenerator.saveGeneratedFiles")))
0085:                    .booleanValue();
0086:
0087:            /**
0088:             * Generate a proxy class given a name and a list of proxy interfaces.
0089:             */
0090:            public static byte[] generateProxyClass(final String name,
0091:                    Class[] interfaces) {
0092:                ProxyGenerator gen = new ProxyGenerator(name, interfaces);
0093:                final byte[] classFile = gen.generateClassFile();
0094:
0095:                if (saveGeneratedFiles) {
0096:                    java.security.AccessController
0097:                            .doPrivileged(new java.security.PrivilegedAction() {
0098:                                public Object run() {
0099:                                    try {
0100:                                        FileOutputStream file = new FileOutputStream(
0101:                                                dotToSlash(name) + ".class");
0102:                                        file.write(classFile);
0103:                                        file.close();
0104:                                        return null;
0105:                                    } catch (IOException e) {
0106:                                        throw new InternalError(
0107:                                                "I/O exception saving generated file: "
0108:                                                        + e);
0109:                                    }
0110:                                }
0111:                            });
0112:                }
0113:
0114:                return classFile;
0115:            }
0116:
0117:            /* preloaded Method objects for methods in java.lang.Object */
0118:            private static Method hashCodeMethod;
0119:            private static Method equalsMethod;
0120:            private static Method toStringMethod;
0121:            static {
0122:                try {
0123:                    hashCodeMethod = Object.class.getMethod("hashCode", null);
0124:                    equalsMethod = Object.class.getMethod("equals",
0125:                            new Class[] { Object.class });
0126:                    toStringMethod = Object.class.getMethod("toString", null);
0127:                } catch (NoSuchMethodException e) {
0128:                    throw new NoSuchMethodError(e.getMessage());
0129:                }
0130:            }
0131:
0132:            /** name of proxy class */
0133:            private String className;
0134:
0135:            /** proxy interfaces */
0136:            private Class[] interfaces;
0137:
0138:            /** constant pool of class being generated */
0139:            private ConstantPool cp = new ConstantPool();
0140:
0141:            /** FieldInfo struct for each field of generated class */
0142:            private List fields = new ArrayList();
0143:
0144:            /** MethodInfo struct for each method of generated class */
0145:            private List methods = new ArrayList();
0146:
0147:            /**
0148:             * for each method to be proxied, maps method name and parameter
0149:             * descriptor to ProxyMethod object
0150:             */
0151:            private Map proxyMethods = new HashMap(11);
0152:
0153:            /**
0154:             * Construct a ProxyGenerator to generate a proxy class with the
0155:             * specified name and for the given interfaces.
0156:             *
0157:             * A ProxyGenerator object contains the state for the ongoing
0158:             * generation of a particular proxy class.
0159:             */
0160:            private ProxyGenerator(String className, Class[] interfaces) {
0161:                this .className = className;
0162:                this .interfaces = interfaces;
0163:            }
0164:
0165:            /**
0166:             * Generate a class file for the proxy class.  This method drives the
0167:             * class file generation process.
0168:             */
0169:            private byte[] generateClassFile() {
0170:
0171:                /* ============================================================
0172:                 * Step 1: Assemble ProxyMethod objects for all methods to
0173:                 * generate proxy dispatching code for.
0174:                 */
0175:
0176:                /*
0177:                 * Record that proxy methods are needed for the hashCode, equals,
0178:                 * and toString methods of java.lang.Object.  This is done before
0179:                 * the methods from the proxy interfaces so that the methods from
0180:                 * java.lang.Object take precedence over duplicate methods in the
0181:                 * proxy interfaces.
0182:                 */
0183:                addProxyMethod(hashCodeMethod, Object.class);
0184:                addProxyMethod(equalsMethod, Object.class);
0185:                addProxyMethod(toStringMethod, Object.class);
0186:
0187:                /*
0188:                 * Now record all of the methods from the proxy interfaces, giving
0189:                 * earlier interfaces precedence over later ones with duplicate
0190:                 * methods.
0191:                 */
0192:                for (int i = 0; i < interfaces.length; i++) {
0193:                    Method[] methods = interfaces[i].getMethods();
0194:                    for (int j = 0; j < methods.length; j++) {
0195:                        addProxyMethod(methods[j], interfaces[i]);
0196:                    }
0197:                }
0198:
0199:                /* ============================================================
0200:                 * Step 2: Assemble FieldInfo and MethodInfo structs for all of
0201:                 * fields and methods in the class we are generating.
0202:                 */
0203:                try {
0204:                    //	    fields.add(new FieldInfo(
0205:                    //		handlerFieldName, "Ljava/lang/reflect/InvocationHandler;",
0206:                    //		RuntimeConstants.ACC_PRIVATE | RuntimeConstants.ACC_FINAL));
0207:
0208:                    methods.add(generateConstructor());
0209:
0210:                    for (Iterator iter = proxyMethods.values().iterator(); iter
0211:                            .hasNext();) {
0212:                        ProxyMethod pm = (ProxyMethod) iter.next();
0213:
0214:                        // add static field for method's Method object
0215:                        fields.add(new FieldInfo(pm.methodFieldName,
0216:                                "Ljava/lang/reflect/Method;",
0217:                                RuntimeConstants.ACC_PRIVATE
0218:                                        | RuntimeConstants.ACC_STATIC));
0219:
0220:                        // generate code for proxy method and add it
0221:                        methods.add(pm.generateMethod());
0222:                    }
0223:
0224:                    methods.add(generateStaticInitializer());
0225:
0226:                } catch (IOException e) {
0227:                    throw new InternalError("unexpected I/O Exception");
0228:                }
0229:
0230:                /* ============================================================
0231:                 * Step 3: Write the final class file.
0232:                 */
0233:
0234:                /*
0235:                 * Make sure that constant pool indexes are reserved for the
0236:                 * following items before starting to write the final class file.
0237:                 */
0238:                cp.getClass(dotToSlash(className));
0239:                cp.getClass(super className);
0240:                for (int i = 0; i < interfaces.length; i++) {
0241:                    cp.getClass(dotToSlash(interfaces[i].getName()));
0242:                }
0243:
0244:                /*
0245:                 * Disallow new constant pool additions beyond this point, since
0246:                 * we are about to write the final constant pool table.
0247:                 */
0248:                cp.setReadOnly();
0249:
0250:                ByteArrayOutputStream bout = new ByteArrayOutputStream();
0251:                DataOutputStream dout = new DataOutputStream(bout);
0252:
0253:                try {
0254:                    /*
0255:                     * Write all the items of the "ClassFile" structure.
0256:                     * See JVMS section 4.1.
0257:                     */
0258:                    // u4 magic;
0259:                    dout.writeInt(RuntimeConstants.JAVA_MAGIC);
0260:                    // u2 major_version;
0261:                    dout
0262:                            .writeShort(RuntimeConstants.JAVA_DEFAULT_MINOR_VERSION);
0263:                    // u2 minor_version;
0264:                    dout.writeShort(RuntimeConstants.JAVA_DEFAULT_VERSION);
0265:
0266:                    cp.write(dout); // (write constant pool)
0267:
0268:                    // u2 access_flags;
0269:                    dout.writeShort(RuntimeConstants.ACC_PUBLIC
0270:                            | RuntimeConstants.ACC_FINAL
0271:                            | RuntimeConstants.ACC_SUPER);
0272:                    // u2 this_class;
0273:                    dout.writeShort(cp.getClass(dotToSlash(className)));
0274:                    // u2 super_class;
0275:                    dout.writeShort(cp.getClass(super className));
0276:
0277:                    // u2 interfaces_count;
0278:                    dout.writeShort(interfaces.length);
0279:                    // u2 interfaces[interfaces_count];
0280:                    for (int i = 0; i < interfaces.length; i++) {
0281:                        dout.writeShort(cp.getClass(dotToSlash(interfaces[i]
0282:                                .getName())));
0283:                    }
0284:
0285:                    // u2 fields_count;
0286:                    dout.writeShort(fields.size());
0287:                    // field_info fields[fields_count];
0288:                    for (Iterator iter = fields.iterator(); iter.hasNext();) {
0289:                        FieldInfo f = (FieldInfo) iter.next();
0290:                        f.write(dout);
0291:                    }
0292:
0293:                    // u2 methods_count;
0294:                    dout.writeShort(methods.size());
0295:                    // method_info methods[methods_count];
0296:                    for (Iterator iter = methods.iterator(); iter.hasNext();) {
0297:                        MethodInfo m = (MethodInfo) iter.next();
0298:                        m.write(dout);
0299:                    }
0300:
0301:                    // u2 attributes_count;
0302:                    dout.writeShort(0); // (no ClassFile attributes for proxy classes)
0303:
0304:                } catch (IOException e) {
0305:                    throw new InternalError("unexpected I/O Exception");
0306:                }
0307:
0308:                return bout.toByteArray();
0309:            }
0310:
0311:            /**
0312:             * Add another method to be proxied, either by creating a new ProxyMethod
0313:             * object or augmenting an old one for a duplicate method.
0314:             *
0315:             * "fromClass" indicates the proxy interface that the method was found
0316:             * through, which may be different from (a subinterface of) the method's
0317:             * "declaring class".  Note that the first Method object passed for a
0318:             * given name and parameter types identifies the Method object (and thus
0319:             * the declaring class) that will be passed to the invocation handler's
0320:             * "invoke" method for a given set of duplicate methods.
0321:             */
0322:            private void addProxyMethod(Method m, Class fromClass) {
0323:                String name = m.getName();
0324:                Class[] parameterTypes = m.getParameterTypes();
0325:                Class returnType = m.getReturnType();
0326:                Class[] exceptionTypes = m.getExceptionTypes();
0327:
0328:                String key = name + getParameterDescriptors(parameterTypes);
0329:                ProxyMethod pm = (ProxyMethod) proxyMethods.get(key);
0330:                if (pm != null) {
0331:                    /*
0332:                     * If a proxy method with the same name and parameter types has
0333:                     * already been added, verify that it has the same return type...
0334:                     */
0335:                    if (returnType != pm.returnType) {
0336:                        throw new IllegalArgumentException(
0337:                                "methods with same name and parameter "
0338:                                        + "signature but different return type in "
0339:                                        + pm.fromClass + " and " + fromClass
0340:                                        + ": " + key);
0341:                    }
0342:                    /*
0343:                     * ...and compute the greatest common set of exceptions that can
0344:                     * thrown by the proxy method compatibly with both inherited
0345:                     * methods.
0346:                     */
0347:                    List legalExceptions = new ArrayList();
0348:                    collectCompatibleTypes(exceptionTypes, pm.exceptionTypes,
0349:                            legalExceptions);
0350:                    collectCompatibleTypes(pm.exceptionTypes, exceptionTypes,
0351:                            legalExceptions);
0352:                    pm.exceptionTypes = new Class[legalExceptions.size()];
0353:                    pm.exceptionTypes = (Class[]) legalExceptions
0354:                            .toArray(pm.exceptionTypes);
0355:                } else {
0356:                    pm = new ProxyMethod(name, parameterTypes, returnType,
0357:                            exceptionTypes, fromClass, "m"
0358:                                    + proxyMethods.size());
0359:                    proxyMethods.put(key, pm);
0360:                }
0361:            }
0362:
0363:            /**
0364:             * A FieldInfo object contains information about a particular field
0365:             * in the class being generated.  The class mirrors the data items of
0366:             * the "field_info" structure of the class file format (see JVMS 4.5).
0367:             */
0368:            private class FieldInfo {
0369:                public int accessFlags;
0370:                public String name;
0371:                public String descriptor;
0372:
0373:                public FieldInfo(String name, String descriptor, int accessFlags) {
0374:                    this .name = name;
0375:                    this .descriptor = descriptor;
0376:                    this .accessFlags = accessFlags;
0377:
0378:                    /*
0379:                     * Make sure that constant pool indexes are reserved for the
0380:                     * following items before starting to write the final class file.
0381:                     */
0382:                    cp.getUtf8(name);
0383:                    cp.getUtf8(descriptor);
0384:                }
0385:
0386:                public void write(DataOutputStream out) throws IOException {
0387:                    /*
0388:                     * Write all the items of the "field_info" structure.
0389:                     * See JVMS section 4.5.
0390:                     */
0391:                    // u2 access_flags;
0392:                    out.writeShort(accessFlags);
0393:                    // u2 name_index;
0394:                    out.writeShort(cp.getUtf8(name));
0395:                    // u2 descriptor_index;
0396:                    out.writeShort(cp.getUtf8(descriptor));
0397:                    // u2 attributes_count;
0398:                    out.writeShort(0); // (no field_info attributes for proxy classes)
0399:                }
0400:            }
0401:
0402:            /**
0403:             * An ExceptionTableEntry object holds values for the data items of
0404:             * an entry in the "exception_table" item of the "Code" attribute of
0405:             * "method_info" structures (see JVMS 4.7.3).
0406:             */
0407:            private static class ExceptionTableEntry {
0408:                public short startPc;
0409:                public short endPc;
0410:                public short handlerPc;
0411:                public short catchType;
0412:
0413:                public ExceptionTableEntry(short startPc, short endPc,
0414:                        short handlerPc, short catchType) {
0415:                    this .startPc = startPc;
0416:                    this .endPc = endPc;
0417:                    this .handlerPc = handlerPc;
0418:                    this .catchType = catchType;
0419:                }
0420:            };
0421:
0422:            /**
0423:             * A MethodInfo object contains information about a particular method
0424:             * in the class being generated.  This class mirrors the data items of
0425:             * the "method_info" structure of the class file format (see JVMS 4.6).
0426:             */
0427:            private class MethodInfo {
0428:                public int accessFlags;
0429:                public String name;
0430:                public String descriptor;
0431:                public short maxStack;
0432:                public short maxLocals;
0433:                public ByteArrayOutputStream code = new ByteArrayOutputStream();
0434:                public List exceptionTable = new ArrayList();
0435:                public short[] declaredExceptions;
0436:
0437:                public MethodInfo(String name, String descriptor,
0438:                        int accessFlags) {
0439:                    this .name = name;
0440:                    this .descriptor = descriptor;
0441:                    this .accessFlags = accessFlags;
0442:
0443:                    /*
0444:                     * Make sure that constant pool indexes are reserved for the
0445:                     * following items before starting to write the final class file.
0446:                     */
0447:                    cp.getUtf8(name);
0448:                    cp.getUtf8(descriptor);
0449:                    cp.getUtf8("Code");
0450:                    cp.getUtf8("Exceptions");
0451:                }
0452:
0453:                public void write(DataOutputStream out) throws IOException {
0454:                    /*
0455:                     * Write all the items of the "method_info" structure.
0456:                     * See JVMS section 4.6.
0457:                     */
0458:                    // u2 access_flags;
0459:                    out.writeShort(accessFlags);
0460:                    // u2 name_index;
0461:                    out.writeShort(cp.getUtf8(name));
0462:                    // u2 descriptor_index;
0463:                    out.writeShort(cp.getUtf8(descriptor));
0464:                    // u2 attributes_count;
0465:                    out.writeShort(2); // (two method_info attributes:)
0466:
0467:                    // Write "Code" attribute. See JVMS section 4.7.3.
0468:
0469:                    // u2 attribute_name_index;
0470:                    out.writeShort(cp.getUtf8("Code"));
0471:                    // u4 attribute_length;
0472:                    out.writeInt(12 + code.size() + 8 * exceptionTable.size());
0473:                    // u2 max_stack;
0474:                    out.writeShort(maxStack);
0475:                    // u2 max_locals;
0476:                    out.writeShort(maxLocals);
0477:                    // u2 code_length;
0478:                    out.writeInt(code.size());
0479:                    // u1 code[code_length];
0480:                    code.writeTo(out);
0481:                    // u2 exception_table_length;
0482:                    out.writeShort(exceptionTable.size());
0483:                    for (Iterator iter = exceptionTable.iterator(); iter
0484:                            .hasNext();) {
0485:                        ExceptionTableEntry e = (ExceptionTableEntry) iter
0486:                                .next();
0487:                        // u2 start_pc;
0488:                        out.writeShort(e.startPc);
0489:                        // u2 end_pc;
0490:                        out.writeShort(e.endPc);
0491:                        // u2 handler_pc;
0492:                        out.writeShort(e.handlerPc);
0493:                        // u2 catch_type;
0494:                        out.writeShort(e.catchType);
0495:                    }
0496:                    // u2 attributes_count;
0497:                    out.writeShort(0);
0498:
0499:                    // write "Exceptions" attribute.  See JVMS section 4.7.4.
0500:
0501:                    // u2 attribute_name_index;
0502:                    out.writeShort(cp.getUtf8("Exceptions"));
0503:                    // u4 attributes_length;
0504:                    out.writeInt(2 + 2 * declaredExceptions.length);
0505:                    // u2 number_of_exceptions;
0506:                    out.writeShort(declaredExceptions.length);
0507:                    // u2 exception_index_table[number_of_exceptions];
0508:                    for (int i = 0; i < declaredExceptions.length; i++) {
0509:                        out.writeShort(declaredExceptions[i]);
0510:                    }
0511:                }
0512:
0513:            }
0514:
0515:            /**
0516:             * A ProxyMethod object represents a proxy method in the proxy class
0517:             * being generated: a method whose implementation will encode and
0518:             * dispatch invocations to the proxy instance's invocation handler.
0519:             */
0520:            private class ProxyMethod {
0521:
0522:                public String methodName;
0523:                public Class[] parameterTypes;
0524:                public Class returnType;
0525:                public Class[] exceptionTypes;
0526:                public Class fromClass;
0527:                public String methodFieldName;
0528:
0529:                private ProxyMethod(String methodName, Class[] parameterTypes,
0530:                        Class returnType, Class[] exceptionTypes,
0531:                        Class fromClass, String methodFieldName) {
0532:                    this .methodName = methodName;
0533:                    this .parameterTypes = parameterTypes;
0534:                    this .returnType = returnType;
0535:                    this .exceptionTypes = exceptionTypes;
0536:                    this .fromClass = fromClass;
0537:                    this .methodFieldName = methodFieldName;
0538:                }
0539:
0540:                /**
0541:                 * Return a MethodInfo object for this method, including generating
0542:                 * the code and exception table entry.
0543:                 */
0544:                private MethodInfo generateMethod() throws IOException {
0545:                    String desc = getMethodDescriptor(parameterTypes,
0546:                            returnType);
0547:                    MethodInfo minfo = new MethodInfo(methodName, desc,
0548:                            RuntimeConstants.ACC_PUBLIC
0549:                                    | RuntimeConstants.ACC_FINAL);
0550:
0551:                    int[] parameterSlot = new int[parameterTypes.length];
0552:                    int nextSlot = 1;
0553:                    for (int i = 0; i < parameterSlot.length; i++) {
0554:                        parameterSlot[i] = nextSlot;
0555:                        nextSlot += getWordsPerType(parameterTypes[i]);
0556:                    }
0557:                    int localSlot0 = nextSlot;
0558:                    short pc, tryBegin = 0, tryEnd;
0559:
0560:                    DataOutputStream out = new DataOutputStream(minfo.code);
0561:
0562:                    code_aload(0, out);
0563:
0564:                    out.writeByte(RuntimeConstants.opc_getfield);
0565:                    out.writeShort(cp.getFieldRef(
0566:                            //		dotToSlash(className),
0567:                            super className, handlerFieldName,
0568:                            "Ljava/lang/reflect/InvocationHandler;"));
0569:
0570:                    code_aload(0, out);
0571:
0572:                    out.writeByte(RuntimeConstants.opc_getstatic);
0573:                    out.writeShort(cp.getFieldRef(dotToSlash(className),
0574:                            methodFieldName, "Ljava/lang/reflect/Method;"));
0575:
0576:                    if (parameterTypes.length > 0) {
0577:
0578:                        code_ipush(parameterTypes.length, out);
0579:
0580:                        out.writeByte(RuntimeConstants.opc_anewarray);
0581:                        out.writeShort(cp.getClass("java/lang/Object"));
0582:
0583:                        for (int i = 0; i < parameterTypes.length; i++) {
0584:
0585:                            out.writeByte(RuntimeConstants.opc_dup);
0586:
0587:                            code_ipush(i, out);
0588:
0589:                            codeWrapArgument(parameterTypes[i],
0590:                                    parameterSlot[i], out);
0591:
0592:                            out.writeByte(RuntimeConstants.opc_aastore);
0593:                        }
0594:                    } else {
0595:
0596:                        out.writeByte(RuntimeConstants.opc_aconst_null);
0597:                    }
0598:
0599:                    out.writeByte(RuntimeConstants.opc_invokeinterface);
0600:                    out
0601:                            .writeShort(cp
0602:                                    .getInterfaceMethodRef(
0603:                                            "java/lang/reflect/InvocationHandler",
0604:                                            "invoke",
0605:                                            "(Ljava/lang/Object;Ljava/lang/reflect/Method;"
0606:                                                    + "[Ljava/lang/Object;)Ljava/lang/Object;"));
0607:                    out.writeByte(4);
0608:                    out.writeByte(0);
0609:
0610:                    if (returnType == void.class) {
0611:
0612:                        out.writeByte(RuntimeConstants.opc_pop);
0613:
0614:                        out.writeByte(RuntimeConstants.opc_return);
0615:
0616:                    } else {
0617:
0618:                        codeUnwrapReturnValue(returnType, out);
0619:                    }
0620:
0621:                    tryEnd = pc = (short) minfo.code.size();
0622:
0623:                    List catchList = computeUniqueCatchList(exceptionTypes);
0624:                    if (catchList.size() > 0) {
0625:
0626:                        for (Iterator iter = catchList.iterator(); iter
0627:                                .hasNext();) {
0628:                            Class ex = (Class) iter.next();
0629:                            minfo.exceptionTable
0630:                                    .add(new ExceptionTableEntry(tryBegin,
0631:                                            tryEnd, pc, cp
0632:                                                    .getClass(dotToSlash(ex
0633:                                                            .getName()))));
0634:                        }
0635:
0636:                        out.writeByte(RuntimeConstants.opc_athrow);
0637:
0638:                        pc = (short) minfo.code.size();
0639:
0640:                        minfo.exceptionTable.add(new ExceptionTableEntry(
0641:                                tryBegin, tryEnd, pc, cp
0642:                                        .getClass("java/lang/Throwable")));
0643:
0644:                        code_astore(localSlot0, out);
0645:
0646:                        out.writeByte(RuntimeConstants.opc_new);
0647:                        out
0648:                                .writeShort(cp
0649:                                        .getClass("java/lang/reflect/UndeclaredThrowableException"));
0650:
0651:                        out.writeByte(RuntimeConstants.opc_dup);
0652:
0653:                        code_aload(localSlot0, out);
0654:
0655:                        out.writeByte(RuntimeConstants.opc_invokespecial);
0656:
0657:                        out
0658:                                .writeShort(cp
0659:                                        .getMethodRef(
0660:                                                "java/lang/reflect/UndeclaredThrowableException",
0661:                                                "<init>",
0662:                                                "(Ljava/lang/Throwable;)V"));
0663:
0664:                        out.writeByte(RuntimeConstants.opc_athrow);
0665:                    }
0666:
0667:                    minfo.maxStack = 10;
0668:                    minfo.maxLocals = (short) (localSlot0 + 1);
0669:                    minfo.declaredExceptions = new short[exceptionTypes.length];
0670:                    for (int i = 0; i < exceptionTypes.length; i++) {
0671:                        minfo.declaredExceptions[i] = cp
0672:                                .getClass(dotToSlash(exceptionTypes[i]
0673:                                        .getName()));
0674:                    }
0675:
0676:                    return minfo;
0677:                }
0678:
0679:                /**
0680:                 * Generate code for wrapping a parameter of the given type and whose
0681:                 * value can be found at the specified local variable index to be
0682:                 * passed to the invocation handler's "invoke" method (as an Object).
0683:                 * The code is written to the supplied stream.
0684:                 */
0685:                private void codeWrapArgument(Class type, int slot,
0686:                        DataOutputStream out) throws IOException {
0687:                    if (type.isPrimitive()) {
0688:                        PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
0689:
0690:                        out.writeByte(RuntimeConstants.opc_new);
0691:                        out.writeShort(cp.getClass(prim.wrapperClassName));
0692:
0693:                        out.writeByte(RuntimeConstants.opc_dup);
0694:
0695:                        if (type == int.class || type == boolean.class
0696:                                || type == byte.class || type == char.class
0697:                                || type == short.class) {
0698:                            code_iload(slot, out);
0699:                        } else if (type == long.class) {
0700:                            code_lload(slot, out);
0701:                        } else if (type == float.class) {
0702:                            code_fload(slot, out);
0703:                        } else if (type == double.class) {
0704:                            code_dload(slot, out);
0705:                        } else {
0706:                            _assert(false);
0707:                        }
0708:
0709:                        out.writeByte(RuntimeConstants.opc_invokespecial);
0710:                        out.writeShort(cp.getMethodRef(prim.wrapperClassName,
0711:                                "<init>", prim.wrapperConstructorDesc));
0712:
0713:                    } else {
0714:
0715:                        code_aload(slot, out);
0716:                    }
0717:                }
0718:
0719:                /**
0720:                 * Generate code for unwrapping the return value of the given type
0721:                 * from the invocation handler's "invoke" method (of type Object) to
0722:                 * its correct type.  The code is written to the supplied stream.
0723:                 */
0724:                private void codeUnwrapReturnValue(Class type,
0725:                        DataOutputStream out) throws IOException {
0726:                    if (type.isPrimitive()) {
0727:                        PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
0728:
0729:                        out.writeByte(RuntimeConstants.opc_checkcast);
0730:                        out.writeShort(cp.getClass(prim.wrapperClassName));
0731:
0732:                        out.writeByte(RuntimeConstants.opc_invokevirtual);
0733:                        out.writeShort(cp.getMethodRef(prim.wrapperClassName,
0734:                                prim.unwrapMethodName, prim.unwrapMethodDesc));
0735:
0736:                        if (type == int.class || type == boolean.class
0737:                                || type == byte.class || type == char.class
0738:                                || type == short.class) {
0739:                            out.writeByte(RuntimeConstants.opc_ireturn);
0740:                        } else if (type == long.class) {
0741:                            out.writeByte(RuntimeConstants.opc_lreturn);
0742:                        } else if (type == float.class) {
0743:                            out.writeByte(RuntimeConstants.opc_freturn);
0744:                        } else if (type == double.class) {
0745:                            out.writeByte(RuntimeConstants.opc_dreturn);
0746:                        } else {
0747:                            _assert(false);
0748:                        }
0749:
0750:                    } else {
0751:
0752:                        out.writeByte(RuntimeConstants.opc_checkcast);
0753:                        out.writeShort(cp.getClass(dotToSlash(type.getName())));
0754:
0755:                        out.writeByte(RuntimeConstants.opc_areturn);
0756:                    }
0757:                }
0758:
0759:                /**
0760:                 * Generate code for initializing the static field that stores
0761:                 * the Method object for this proxy method.  The code is written
0762:                 * to the supplied stream.
0763:                 */
0764:                private void codeFieldInitialization(DataOutputStream out)
0765:                        throws IOException {
0766:                    codeClassForName(fromClass, out);
0767:
0768:                    code_ldc(cp.getString(methodName), out);
0769:
0770:                    code_ipush(parameterTypes.length, out);
0771:
0772:                    out.writeByte(RuntimeConstants.opc_anewarray);
0773:                    out.writeShort(cp.getClass("java/lang/Class"));
0774:
0775:                    for (int i = 0; i < parameterTypes.length; i++) {
0776:
0777:                        out.writeByte(RuntimeConstants.opc_dup);
0778:
0779:                        code_ipush(i, out);
0780:
0781:                        if (parameterTypes[i].isPrimitive()) {
0782:                            PrimitiveTypeInfo prim = PrimitiveTypeInfo
0783:                                    .get(parameterTypes[i]);
0784:
0785:                            out.writeByte(RuntimeConstants.opc_getstatic);
0786:                            out.writeShort(cp.getFieldRef(
0787:                                    prim.wrapperClassName, "TYPE",
0788:                                    "Ljava/lang/Class;"));
0789:
0790:                        } else {
0791:                            codeClassForName(parameterTypes[i], out);
0792:                        }
0793:
0794:                        out.writeByte(RuntimeConstants.opc_aastore);
0795:                    }
0796:
0797:                    out.writeByte(RuntimeConstants.opc_invokevirtual);
0798:                    out.writeShort(cp.getMethodRef("java/lang/Class",
0799:                            "getMethod",
0800:                            "(Ljava/lang/String;[Ljava/lang/Class;)"
0801:                                    + "Ljava/lang/reflect/Method;"));
0802:
0803:                    out.writeByte(RuntimeConstants.opc_putstatic);
0804:                    out.writeShort(cp.getFieldRef(dotToSlash(className),
0805:                            methodFieldName, "Ljava/lang/reflect/Method;"));
0806:                }
0807:            }
0808:
0809:            /**
0810:             * Generate the constructor method for the proxy class.
0811:             */
0812:            private MethodInfo generateConstructor() throws IOException {
0813:                MethodInfo minfo = new MethodInfo("<init>",
0814:                        "(Ljava/lang/reflect/InvocationHandler;)V",
0815:                        RuntimeConstants.ACC_PUBLIC);
0816:
0817:                DataOutputStream out = new DataOutputStream(minfo.code);
0818:
0819:                code_aload(0, out);
0820:
0821:                code_aload(1, out);
0822:
0823:                out.writeByte(RuntimeConstants.opc_invokespecial);
0824:                out.writeShort(cp.getMethodRef(super className, "<init>",
0825:                        "(Ljava/lang/reflect/InvocationHandler;)V"));
0826:
0827:                //	code_aload(0, out);
0828:                //
0829:                //	code_aload(1, out);
0830:                //
0831:                //	out.writeByte(RuntimeConstants.opc_putfield);
0832:                //	out.writeShort(cp.getFieldRef(
0833:                //	    dotToSlash(className),
0834:                //	    handlerFieldName, "Ljava/lang/reflect/InvocationHandler;"));
0835:
0836:                out.writeByte(RuntimeConstants.opc_return);
0837:
0838:                minfo.maxStack = 10;
0839:                minfo.maxLocals = 2;
0840:                minfo.declaredExceptions = new short[0];
0841:
0842:                return minfo;
0843:            }
0844:
0845:            /**
0846:             * Generate the static initializer method for the proxy class.
0847:             */
0848:            private MethodInfo generateStaticInitializer() throws IOException {
0849:                MethodInfo minfo = new MethodInfo("<clinit>", "()V",
0850:                        RuntimeConstants.ACC_STATIC);
0851:
0852:                int localSlot0 = 1;
0853:                short pc, tryBegin = 0, tryEnd;
0854:
0855:                DataOutputStream out = new DataOutputStream(minfo.code);
0856:
0857:                for (Iterator iter = proxyMethods.values().iterator(); iter
0858:                        .hasNext();) {
0859:                    ProxyMethod pm = (ProxyMethod) iter.next();
0860:                    pm.codeFieldInitialization(out);
0861:                }
0862:
0863:                out.writeByte(RuntimeConstants.opc_return);
0864:
0865:                tryEnd = pc = (short) minfo.code.size();
0866:
0867:                minfo.exceptionTable.add(new ExceptionTableEntry(tryBegin,
0868:                        tryEnd, pc, cp
0869:                                .getClass("java/lang/NoSuchMethodException")));
0870:
0871:                code_astore(localSlot0, out);
0872:
0873:                out.writeByte(RuntimeConstants.opc_new);
0874:                out.writeShort(cp.getClass("java/lang/NoSuchMethodError"));
0875:
0876:                out.writeByte(RuntimeConstants.opc_dup);
0877:
0878:                code_aload(localSlot0, out);
0879:
0880:                out.writeByte(RuntimeConstants.opc_invokevirtual);
0881:                out.writeShort(cp.getMethodRef("java/lang/Throwable",
0882:                        "getMessage", "()Ljava/lang/String;"));
0883:
0884:                out.writeByte(RuntimeConstants.opc_invokespecial);
0885:                out.writeShort(cp.getMethodRef("java/lang/NoSuchMethodError",
0886:                        "<init>", "(Ljava/lang/String;)V"));
0887:
0888:                out.writeByte(RuntimeConstants.opc_athrow);
0889:
0890:                pc = (short) minfo.code.size();
0891:
0892:                minfo.exceptionTable.add(new ExceptionTableEntry(tryBegin,
0893:                        tryEnd, pc, cp
0894:                                .getClass("java/lang/ClassNotFoundException")));
0895:
0896:                code_astore(localSlot0, out);
0897:
0898:                out.writeByte(RuntimeConstants.opc_new);
0899:                out.writeShort(cp.getClass("java/lang/NoClassDefFoundError"));
0900:
0901:                out.writeByte(RuntimeConstants.opc_dup);
0902:
0903:                code_aload(localSlot0, out);
0904:
0905:                out.writeByte(RuntimeConstants.opc_invokevirtual);
0906:                out.writeShort(cp.getMethodRef("java/lang/Throwable",
0907:                        "getMessage", "()Ljava/lang/String;"));
0908:
0909:                out.writeByte(RuntimeConstants.opc_invokespecial);
0910:                out.writeShort(cp.getMethodRef(
0911:                        "java/lang/NoClassDefFoundError", "<init>",
0912:                        "(Ljava/lang/String;)V"));
0913:
0914:                out.writeByte(RuntimeConstants.opc_athrow);
0915:
0916:                minfo.maxStack = 10;
0917:                minfo.maxLocals = (short) (localSlot0 + 1);
0918:                minfo.declaredExceptions = new short[0];
0919:
0920:                return minfo;
0921:            }
0922:
0923:            /*
0924:             * =============== Code Generation Utility Methods ===============
0925:             */
0926:
0927:            /*
0928:             * The following methods generate code for the load or store operation
0929:             * indicated by their name for the given local variable.  The code is
0930:             * written to the supplied stream.
0931:             */
0932:
0933:            private void code_iload(int lvar, DataOutputStream out)
0934:                    throws IOException {
0935:                codeLocalLoadStore(lvar, RuntimeConstants.opc_iload,
0936:                        RuntimeConstants.opc_iload_0, out);
0937:            }
0938:
0939:            private void code_lload(int lvar, DataOutputStream out)
0940:                    throws IOException {
0941:                codeLocalLoadStore(lvar, RuntimeConstants.opc_lload,
0942:                        RuntimeConstants.opc_lload_0, out);
0943:            }
0944:
0945:            private void code_fload(int lvar, DataOutputStream out)
0946:                    throws IOException {
0947:                codeLocalLoadStore(lvar, RuntimeConstants.opc_fload,
0948:                        RuntimeConstants.opc_fload_0, out);
0949:            }
0950:
0951:            private void code_dload(int lvar, DataOutputStream out)
0952:                    throws IOException {
0953:                codeLocalLoadStore(lvar, RuntimeConstants.opc_dload,
0954:                        RuntimeConstants.opc_dload_0, out);
0955:            }
0956:
0957:            private void code_aload(int lvar, DataOutputStream out)
0958:                    throws IOException {
0959:                codeLocalLoadStore(lvar, RuntimeConstants.opc_aload,
0960:                        RuntimeConstants.opc_aload_0, out);
0961:            }
0962:
0963:            private void code_istore(int lvar, DataOutputStream out)
0964:                    throws IOException {
0965:                codeLocalLoadStore(lvar, RuntimeConstants.opc_istore,
0966:                        RuntimeConstants.opc_istore_0, out);
0967:            }
0968:
0969:            /* 6220850
0970:            private void code_lstore(int lvar, DataOutputStream out)
0971:            throws IOException
0972:            {
0973:            codeLocalLoadStore(lvar,
0974:                RuntimeConstants.opc_lstore, RuntimeConstants.opc_lstore_0, out);
0975:            }
0976:
0977:            private void code_fstore(int lvar, DataOutputStream out)
0978:            throws IOException
0979:            {
0980:            codeLocalLoadStore(lvar,
0981:                RuntimeConstants.opc_fstore, RuntimeConstants.opc_fstore_0, out);
0982:            }
0983:
0984:            private void code_dstore(int lvar, DataOutputStream out)
0985:            throws IOException
0986:            {
0987:            codeLocalLoadStore(lvar,
0988:                RuntimeConstants.opc_dstore, RuntimeConstants.opc_dstore_0, out);
0989:            }
0990:            6220850 */
0991:
0992:            private void code_astore(int lvar, DataOutputStream out)
0993:                    throws IOException {
0994:                codeLocalLoadStore(lvar, RuntimeConstants.opc_astore,
0995:                        RuntimeConstants.opc_astore_0, out);
0996:            }
0997:
0998:            /**
0999:             * Generate code for a load or store instruction for the given local
1000:             * variable.  The code is written to the supplied stream.
1001:             *
1002:             * "opcode" indicates the opcode form of the desired load or store
1003:             * instruction that takes an explicit local variable index, and
1004:             * "opcode_0" indicates the corresponding form of the instruction
1005:             * with the implicit index 0.
1006:             */
1007:            private void codeLocalLoadStore(int lvar, int opcode, int opcode_0,
1008:                    DataOutputStream out) throws IOException {
1009:                _assert(lvar >= 0 && lvar <= 0xFFFF);
1010:                if (lvar <= 3) {
1011:                    out.writeByte(opcode_0 + lvar);
1012:                } else if (lvar <= 0xFF) {
1013:                    out.writeByte(opcode);
1014:                    out.writeByte(lvar & 0xFF);
1015:                } else {
1016:                    /*
1017:                     * Use the "wide" instruction modifier for local variable
1018:                     * indexes that do not fit into an unsigned byte.
1019:                     */
1020:                    out.writeByte(RuntimeConstants.opc_wide);
1021:                    out.writeByte(opcode);
1022:                    out.writeShort(lvar & 0xFFFF);
1023:                }
1024:            }
1025:
1026:            /**
1027:             * Generate code for an "ldc" instruction for the given constant pool
1028:             * index (the "ldc_w" instruction is used if the index does not fit
1029:             * into an unsigned byte).  The code is written to the supplied stream.
1030:             */
1031:            private void code_ldc(int index, DataOutputStream out)
1032:                    throws IOException {
1033:                _assert(index >= 0 && index <= 0xFFFF);
1034:                if (index <= 0xFF) {
1035:                    out.writeByte(RuntimeConstants.opc_ldc);
1036:                    out.writeByte(index & 0xFF);
1037:                } else {
1038:                    out.writeByte(RuntimeConstants.opc_ldc_w);
1039:                    out.writeShort(index & 0xFFFF);
1040:                }
1041:            }
1042:
1043:            /**
1044:             * Generate code to push a constant integer value on to the operand
1045:             * stack, using the "iconst_<i>", "bipush", or "sipush" instructions
1046:             * depending on the size of the value.  The code is written to the
1047:             * supplied stream.
1048:             */
1049:            private void code_ipush(int value, DataOutputStream out)
1050:                    throws IOException {
1051:                if (value >= -1 && value <= 5) {
1052:                    out.writeByte(RuntimeConstants.opc_iconst_0 + value);
1053:                } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
1054:                    out.writeByte(RuntimeConstants.opc_bipush);
1055:                    out.writeByte(value & 0xFF);
1056:                } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
1057:                    out.writeByte(RuntimeConstants.opc_sipush);
1058:                    out.writeShort(value & 0xFFFF);
1059:                } else {
1060:                    _assert(false);
1061:                }
1062:            }
1063:
1064:            /**
1065:             * Generate code to invoke the Class.forName with the name of the given
1066:             * class to get its Class object at runtime.  The code is written to
1067:             * the supplied stream.  Note that the code generated by this method
1068:             * may caused the checked ClassNotFoundException to be thrown.
1069:             */
1070:            private void codeClassForName(Class cl, DataOutputStream out)
1071:                    throws IOException {
1072:                code_ldc(cp.getString(cl.getName()), out);
1073:
1074:                out.writeByte(RuntimeConstants.opc_invokestatic);
1075:                out.writeShort(cp.getMethodRef("java/lang/Class", "forName",
1076:                        "(Ljava/lang/String;)Ljava/lang/Class;"));
1077:            }
1078:
1079:            /*
1080:             * ==================== General Utility Methods ====================
1081:             */
1082:
1083:            /**
1084:             * Assert that an assertion is true: throw InternalError if it is not.
1085:             */
1086:            private static void _assert(boolean assertion) {
1087:                if (assertion != true) {
1088:                    throw new InternalError("assertion failure");
1089:                }
1090:            }
1091:
1092:            /**
1093:             * Convert a fully qualified class name that uses '.' as the package
1094:             * separator, the external representation used by the Java language
1095:             * and APIs, to a fully qualified class name that uses '/' as the
1096:             * package separator, the representation used in the class file
1097:             * format (see JVMS section 4.2).
1098:             */
1099:            private static String dotToSlash(String name) {
1100:                return name.replace('.', '/');
1101:            }
1102:
1103:            /**
1104:             * Return the "method descriptor" string for a method with the given
1105:             * parameter types and return type.  See JVMS section 4.3.3.
1106:             */
1107:            private static String getMethodDescriptor(Class[] parameterTypes,
1108:                    Class returnType) {
1109:                return getParameterDescriptors(parameterTypes)
1110:                        + ((returnType == void.class) ? "V"
1111:                                : getFieldType(returnType));
1112:            }
1113:
1114:            /**
1115:             * Return the list of "parameter descriptor" strings enclosed in
1116:             * parentheses corresponding to the given parameter types (in other
1117:             * words, a method descriptor without a return descriptor).  This
1118:             * string is useful for constructing string keys for methods without
1119:             * regard to their return type.
1120:             */
1121:            private static String getParameterDescriptors(Class[] parameterTypes) {
1122:                StringBuffer desc = new StringBuffer("(");
1123:                for (int i = 0; i < parameterTypes.length; i++) {
1124:                    desc.append(getFieldType(parameterTypes[i]));
1125:                }
1126:                desc.append(')');
1127:                return desc.toString();
1128:            }
1129:
1130:            /**
1131:             * Return the "field type" string for the given type, appropriate for
1132:             * a field descriptor, a parameter descriptor, or a return descriptor
1133:             * other than "void".  See JVMS section 4.3.2.
1134:             */
1135:            private static String getFieldType(Class type) {
1136:                if (type.isPrimitive()) {
1137:                    return PrimitiveTypeInfo.get(type).baseTypeString;
1138:                } else if (type.isArray()) {
1139:                    /*
1140:                     * According to JLS 20.3.2, the getName() method on Class does
1141:                     * return the VM type descriptor format for array classes (only);
1142:                     * using that should be quicker than the otherwise obvious code:
1143:                     *
1144:                     *     return "[" + getTypeDescriptor(type.getComponentType());
1145:                     */
1146:                    return type.getName().replace('.', '/');
1147:                } else {
1148:                    return "L" + dotToSlash(type.getName()) + ";";
1149:                }
1150:            }
1151:
1152:            /**
1153:             * Return the number of abstract "words", or consecutive local variable
1154:             * indexes, required to contain a value of the given type.  See JVMS
1155:             * section 3.6.1.
1156:             *
1157:             * Note that the original version of the JVMS contained a definition of
1158:             * this abstract notion of a "word" in section 3.4, but that definition
1159:             * was removed for the second edition.
1160:             */
1161:            private static int getWordsPerType(Class type) {
1162:                if (type == long.class || type == double.class) {
1163:                    return 2;
1164:                } else {
1165:                    return 1;
1166:                }
1167:            }
1168:
1169:            /**
1170:             * Add to the given list all of the types in the "from" array that
1171:             * are not already contained in the liast and are assignable to at
1172:             * least one of the types in the "with" array.
1173:             *
1174:             * This method is useful for computing the greatest common set of
1175:             * declared exceptions from duplicate methods inherited from
1176:             * different interfaces.
1177:             */
1178:            private static void collectCompatibleTypes(Class[] from,
1179:                    Class[] with, List list) {
1180:                for (int i = 0; i < from.length; i++) {
1181:                    if (!list.contains(from[i])) {
1182:                        for (int j = 0; j < with.length; j++) {
1183:                            if (with[j].isAssignableFrom(from[i])) {
1184:                                list.add(from[i]);
1185:                                break;
1186:                            }
1187:                        }
1188:                    }
1189:                }
1190:            }
1191:
1192:            /**
1193:             * Given the exceptions declared in the throws clause of a proxy method,
1194:             * compute the exceptions that need to be caught from the invocation
1195:             * handler's invoke method and rethrown intact in the method's
1196:             * implementation before catching other Throwables and wrapping them
1197:             * in UndeclaredThrowableExceptions.
1198:             *
1199:             * The exceptions to be caught are returned in a List object.  Each
1200:             * exception in the returned list is guaranteed to not be a subclass of
1201:             * any of the other exceptions in the list, so the catch blocks for
1202:             * these exceptions may be generated in any order relative to each other.
1203:             *
1204:             * Error and RuntimeException are each always contained by the returned
1205:             * list (if none of their superclasses are contained), since those
1206:             * unchecked exceptions should always be rethrown intact, and thus their
1207:             * subclasses will never appear in the returned list.
1208:             *
1209:             * The returned List will be empty if java.lang.Throwable is in the
1210:             * given list of declared exceptions, indicating that no exceptions
1211:             * need to be caught.
1212:             */
1213:            private static List computeUniqueCatchList(Class[] exceptions) {
1214:                List uniqueList = new ArrayList(); // unique exceptions to catch
1215:
1216:                uniqueList.add(Error.class); // always catch/rethrow these
1217:                uniqueList.add(RuntimeException.class);
1218:
1219:                nextException: for (int i = 0; i < exceptions.length; i++) {
1220:                    Class ex = exceptions[i];
1221:                    if (ex.isAssignableFrom(Throwable.class)) {
1222:                        /*
1223:                         * If Throwable is declared to be thrown by the proxy method,
1224:                         * then no catch blocks are necessary, because the invoke
1225:                         * can, at most, throw Throwable anyway.
1226:                         */
1227:                        uniqueList.clear();
1228:                        break;
1229:                    } else if (!Throwable.class.isAssignableFrom(ex)) {
1230:                        /*
1231:                         * Ignore types that cannot be thrown by the invoke method.
1232:                         */
1233:                        continue;
1234:                    }
1235:                    /*
1236:                     * Compare this exception against the current list of
1237:                     * exceptions that need to be caught:
1238:                     */
1239:                    for (int j = 0; j < uniqueList.size();) {
1240:                        Class ex2 = (Class) uniqueList.get(j);
1241:                        if (ex2.isAssignableFrom(ex)) {
1242:                            /*
1243:                             * if a superclass of this exception is already on
1244:                             * the list to catch, then ignore this one and continue;
1245:                             */
1246:                            continue nextException;
1247:                        } else if (ex.isAssignableFrom(ex2)) {
1248:                            /*
1249:                             * if a subclass of this exception is on the list
1250:                             * to catch, then remove it;
1251:                             */
1252:                            uniqueList.remove(j);
1253:                        } else {
1254:                            j++; // else continue comparing.
1255:                        }
1256:                    }
1257:                    // This exception is unique (so far): add it to the list to catch.
1258:                    uniqueList.add(ex);
1259:                }
1260:                return uniqueList;
1261:            }
1262:
1263:            /**
1264:             * A PrimitiveTypeInfo object contains assorted information about
1265:             * a primitive type in its public fields.  The struct for a particular
1266:             * primitive type can be obtained using the static "get" method.
1267:             */
1268:            private static class PrimitiveTypeInfo {
1269:
1270:                /** "base type" used in various descriptors (see JVMS section 4.3.2) */
1271:                public String baseTypeString;
1272:
1273:                /** name of corresponding wrapper class */
1274:                public String wrapperClassName;
1275:
1276:                /** method descriptor for wrapper class constructor */
1277:                public String wrapperConstructorDesc;
1278:
1279:                /** name of wrapper class method for retrieving primitive value */
1280:                public String unwrapMethodName;
1281:
1282:                /** descriptor of same method */
1283:                public String unwrapMethodDesc;
1284:
1285:                private static Map table = new HashMap(11);
1286:                static {
1287:                    table.put(int.class, new PrimitiveTypeInfo("I",
1288:                            "java/lang/Integer", "(I)V", "intValue", "()I"));
1289:                    table
1290:                            .put(boolean.class, new PrimitiveTypeInfo("Z",
1291:                                    "java/lang/Boolean", "(Z)V",
1292:                                    "booleanValue", "()Z"));
1293:                    table.put(byte.class, new PrimitiveTypeInfo("B",
1294:                            "java/lang/Byte", "(B)V", "byteValue", "()B"));
1295:                    table.put(char.class, new PrimitiveTypeInfo("C",
1296:                            "java/lang/Character", "(C)V", "charValue", "()C"));
1297:                    table.put(short.class, new PrimitiveTypeInfo("S",
1298:                            "java/lang/Short", "(S)V", "shortValue", "()S"));
1299:                    table.put(long.class, new PrimitiveTypeInfo("J",
1300:                            "java/lang/Long", "(J)V", "longValue", "()J"));
1301:                    table.put(float.class, new PrimitiveTypeInfo("F",
1302:                            "java/lang/Float", "(F)V", "floatValue", "()F"));
1303:                    table.put(double.class, new PrimitiveTypeInfo("D",
1304:                            "java/lang/Double", "(D)V", "doubleValue", "()D"));
1305:                }
1306:
1307:                private PrimitiveTypeInfo(String baseTypeString,
1308:                        String wrapperClassName, String wrapperConstructorDesc,
1309:                        String unwrapMethodName, String unwrapMethodDesc) {
1310:                    this .baseTypeString = baseTypeString;
1311:                    this .wrapperClassName = wrapperClassName;
1312:                    this .wrapperConstructorDesc = wrapperConstructorDesc;
1313:                    this .unwrapMethodName = unwrapMethodName;
1314:                    this .unwrapMethodDesc = unwrapMethodDesc;
1315:                }
1316:
1317:                public static PrimitiveTypeInfo get(Class cl) {
1318:                    return (PrimitiveTypeInfo) table.get(cl);
1319:                }
1320:            }
1321:
1322:            /**
1323:             * A ConstantPool object represents the constant pool of a class file
1324:             * being generated.  This representation of a constant pool is designed
1325:             * specifically for use by ProxyGenerator; in particular, it assumes
1326:             * that constant pool entries will not need to be resorted (for example,
1327:             * by their type, as the Java compiler does), so that the final index
1328:             * value can be assigned and used when an entry is first created.
1329:             *
1330:             * Note that new entries cannot be created after the constant pool has
1331:             * been written to a class file.  To prevent such logic errors, a
1332:             * ConstantPool instance can be marked "read only", so that further
1333:             * attempts to add new entries will fail with a runtime exception.
1334:             *
1335:             * See JVMS section 4.4 for more information about the constant pool
1336:             * of a class file.
1337:             */
1338:            private static class ConstantPool {
1339:
1340:                /**
1341:                 * list of constant pool entries, in constant pool index order.
1342:                 *
1343:                 * This list is used when writing the constant pool to a stream
1344:                 * and for assigning the next index value.  Note that element 0
1345:                 * of this list corresponds to constant pool index 1.
1346:                 */
1347:                private List pool = new ArrayList(32);
1348:
1349:                /**
1350:                 * maps constant pool data of all types to constant pool indexes.
1351:                 *
1352:                 * This map is used to look up the index of an existing entry for
1353:                 * values of all types.
1354:                 */
1355:                private Map map = new HashMap(16);
1356:
1357:                /** true if no new constant pool entries may be added */
1358:                private boolean readOnly = false;
1359:
1360:                /**
1361:                 * Get or assign the index for a CONSTANT_Utf8 entry.
1362:                 */
1363:                public short getUtf8(String s) {
1364:                    if (s == null) {
1365:                        throw new NullPointerException();
1366:                    }
1367:                    return getValue(s);
1368:                }
1369:
1370:                /**
1371:                 * Get or assign the index for a CONSTANT_Integer entry.
1372:                 */
1373:                public short getInteger(int i) {
1374:                    return getValue(new Integer(i));
1375:                }
1376:
1377:                /**
1378:                 * Get or assign the index for a CONSTANT_Float entry.
1379:                 */
1380:                public short getFloat(float f) {
1381:                    return getValue(new Float(f));
1382:                }
1383:
1384:                /**
1385:                 * Get or assign the index for a CONSTANT_Long entry.
1386:                 */
1387:                public short getLong(long l) {
1388:                    return getValue(new Long(l));
1389:                }
1390:
1391:                /**
1392:                 * Get or assign the index for a CONSTANT_Double entry.
1393:                 */
1394:                public short getDouble(double d) {
1395:                    return getValue(new Double(d));
1396:                }
1397:
1398:                /**
1399:                 * Get or assign the index for a CONSTANT_Class entry.
1400:                 */
1401:                public short getClass(String name) {
1402:                    short utf8Index = getUtf8(name);
1403:                    return getIndirect(new IndirectEntry(
1404:                            RuntimeConstants.CONSTANT_CLASS, utf8Index));
1405:                }
1406:
1407:                /**
1408:                 * Get or assign the index for a CONSTANT_String entry.
1409:                 */
1410:                public short getString(String s) {
1411:                    short utf8Index = getUtf8(s);
1412:                    return getIndirect(new IndirectEntry(
1413:                            RuntimeConstants.CONSTANT_STRING, utf8Index));
1414:                }
1415:
1416:                /**
1417:                 * Get or assign the index for a CONSTANT_FieldRef entry.
1418:                 */
1419:                public short getFieldRef(String className, String name,
1420:                        String descriptor) {
1421:                    short classIndex = getClass(className);
1422:                    short nameAndTypeIndex = getNameAndType(name, descriptor);
1423:                    return getIndirect(new IndirectEntry(
1424:                            RuntimeConstants.CONSTANT_FIELD, classIndex,
1425:                            nameAndTypeIndex));
1426:                }
1427:
1428:                /**
1429:                 * Get or assign the index for a CONSTANT_MethodRef entry.
1430:                 */
1431:                public short getMethodRef(String className, String name,
1432:                        String descriptor) {
1433:                    short classIndex = getClass(className);
1434:                    short nameAndTypeIndex = getNameAndType(name, descriptor);
1435:                    return getIndirect(new IndirectEntry(
1436:                            RuntimeConstants.CONSTANT_METHOD, classIndex,
1437:                            nameAndTypeIndex));
1438:                }
1439:
1440:                /**
1441:                 * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
1442:                 */
1443:                public short getInterfaceMethodRef(String className,
1444:                        String name, String descriptor) {
1445:                    short classIndex = getClass(className);
1446:                    short nameAndTypeIndex = getNameAndType(name, descriptor);
1447:                    return getIndirect(new IndirectEntry(
1448:                            RuntimeConstants.CONSTANT_INTERFACEMETHOD,
1449:                            classIndex, nameAndTypeIndex));
1450:                }
1451:
1452:                /**
1453:                 * Get or assign the index for a CONSTANT_NameAndType entry.
1454:                 */
1455:                public short getNameAndType(String name, String descriptor) {
1456:                    short nameIndex = getUtf8(name);
1457:                    short descriptorIndex = getUtf8(descriptor);
1458:                    return getIndirect(new IndirectEntry(
1459:                            RuntimeConstants.CONSTANT_NAMEANDTYPE, nameIndex,
1460:                            descriptorIndex));
1461:                }
1462:
1463:                /**
1464:                 * Set this ConstantPool instance to be "read only".
1465:                 *
1466:                 * After this method has been called, further requests to get
1467:                 * an index for a non-existent entry will cause an InternalError
1468:                 * to be thrown instead of creating of the entry.
1469:                 */
1470:                public void setReadOnly() {
1471:                    readOnly = true;
1472:                }
1473:
1474:                /**
1475:                 * Write this constant pool to a stream as part of
1476:                 * the class file format.
1477:                 *
1478:                 * This consists of writing the "constant_pool_count" and
1479:                 * "constant_pool[]" items of the "ClassFile" structure, as
1480:                 * described in JVMS section 4.1.
1481:                 */
1482:                public void write(OutputStream out) throws IOException {
1483:                    DataOutputStream dataOut = new DataOutputStream(out);
1484:
1485:                    // constant_pool_count: number of entries plus one
1486:                    dataOut.writeShort(pool.size() + 1);
1487:
1488:                    for (Iterator iter = pool.iterator(); iter.hasNext();) {
1489:                        Entry e = (Entry) iter.next();
1490:                        e.write(dataOut);
1491:                    }
1492:                }
1493:
1494:                /**
1495:                 * Add a new constant pool entry and return its index.
1496:                 */
1497:                private short addEntry(Entry entry) {
1498:                    pool.add(entry);
1499:                    return (short) pool.size();
1500:                }
1501:
1502:                /**
1503:                 * Get or assign the index for an entry of a type that contains
1504:                 * a direct value.  The type of the given object determines the
1505:                 * type of the desired entry as follows:
1506:                 * 
1507:                 *	java.lang.String	CONSTANT_Utf8
1508:                 *	java.lang.Integer	CONSTANT_Integer
1509:                 *	java.lang.Float		CONSTANT_Float
1510:                 *	java.lang.Long		CONSTANT_Long
1511:                 *	java.lang.Double	CONSTANT_DOUBLE
1512:                 */
1513:                private short getValue(Object key) {
1514:                    Short index = (Short) map.get(key);
1515:                    if (index != null) {
1516:                        return index.shortValue();
1517:                    } else {
1518:                        if (readOnly) {
1519:                            throw new InternalError(
1520:                                    "late constant pool addition: " + key);
1521:                        }
1522:                        short i = addEntry(new ValueEntry(key));
1523:                        map.put(key, new Short(i));
1524:                        return i;
1525:                    }
1526:                }
1527:
1528:                /**
1529:                 * Get or assign the index for an entry of a type that contains
1530:                 * references to other constant pool entries.
1531:                 */
1532:                private short getIndirect(IndirectEntry e) {
1533:                    Short index = (Short) map.get(e);
1534:                    if (index != null) {
1535:                        return index.shortValue();
1536:                    } else {
1537:                        if (readOnly) {
1538:                            throw new InternalError(
1539:                                    "late constant pool addition");
1540:                        }
1541:                        short i = addEntry(e);
1542:                        map.put(e, new Short(i));
1543:                        return i;
1544:                    }
1545:                }
1546:
1547:                /**
1548:                 * Entry is the abstact superclass of all constant pool entry types
1549:                 * that can be stored in the "pool" list; its purpose is to define a
1550:                 * common method for writing constant pool entries to a class file.
1551:                 */
1552:                private static abstract class Entry {
1553:                    public abstract void write(DataOutputStream out)
1554:                            throws IOException;
1555:                }
1556:
1557:                /**
1558:                 * ValueEntry represents a constant pool entry of a type that
1559:                 * contains a direct value (see the comments for the "getValue"
1560:                 * method for a list of such types).
1561:                 *
1562:                 * ValueEntry objects are not used as keys for their entries in the
1563:                 * Map "map", so no useful hashCode or equals methods are defined.
1564:                 */
1565:                private static class ValueEntry extends Entry {
1566:                    private Object value;
1567:
1568:                    public ValueEntry(Object value) {
1569:                        this .value = value;
1570:                    }
1571:
1572:                    public void write(DataOutputStream out) throws IOException {
1573:                        if (value instanceof  String) {
1574:                            out.writeByte(RuntimeConstants.CONSTANT_UTF8);
1575:                            out.writeUTF((String) value);
1576:                        } else if (value instanceof  Integer) {
1577:                            out.writeByte(RuntimeConstants.CONSTANT_INTEGER);
1578:                            out.writeInt(((Integer) value).intValue());
1579:                        } else if (value instanceof  Float) {
1580:                            out.writeByte(RuntimeConstants.CONSTANT_FLOAT);
1581:                            out.writeFloat(((Float) value).floatValue());
1582:                        } else if (value instanceof  Long) {
1583:                            out.writeByte(RuntimeConstants.CONSTANT_LONG);
1584:                            out.writeLong(((Long) value).longValue());
1585:                        } else if (value instanceof  Double) {
1586:                            out.writeDouble(RuntimeConstants.CONSTANT_DOUBLE);
1587:                            out.writeDouble(((Double) value).doubleValue());
1588:                        } else {
1589:                            throw new InternalError("bogus value entry: "
1590:                                    + value);
1591:                        }
1592:                    }
1593:                }
1594:
1595:                /**
1596:                 * IndirectEntry represents a constant pool entry of a type that
1597:                 * references other constant pool entries, i.e., the following types:
1598:                 *
1599:                 *	CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
1600:                 *	CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
1601:                 *	CONSTANT_NameAndType.
1602:                 *
1603:                 * Each of these entry types contains either one or two indexes of
1604:                 * other constant pool entries.
1605:                 *
1606:                 * IndirectEntry objects are used as the keys for their entries in
1607:                 * the Map "map", so the hashCode and equals methods are overridden
1608:                 * to allow matching.
1609:                 */
1610:                private static class IndirectEntry extends Entry {
1611:                    private int tag;
1612:                    private short index0;
1613:                    private short index1;
1614:
1615:                    /**
1616:                     * Construct an IndirectEntry for a constant pool entry type
1617:                     * that contains one index of another entry.
1618:                     */
1619:                    public IndirectEntry(int tag, short index) {
1620:                        this .tag = tag;
1621:                        this .index0 = index;
1622:                        this .index1 = 0;
1623:                    }
1624:
1625:                    /**
1626:                     * Construct an IndirectEntry for a constant pool entry type
1627:                     * that contains two indexes for other entries.
1628:                     */
1629:                    public IndirectEntry(int tag, short index0, short index1) {
1630:                        this .tag = tag;
1631:                        this .index0 = index0;
1632:                        this .index1 = index1;
1633:                    }
1634:
1635:                    public void write(DataOutputStream out) throws IOException {
1636:                        out.writeByte(tag);
1637:                        out.writeShort(index0);
1638:                        /*
1639:                         * If this entry type contains two indexes, write
1640:                         * out the second, too.
1641:                         */
1642:                        if (tag == RuntimeConstants.CONSTANT_FIELD
1643:                                || tag == RuntimeConstants.CONSTANT_METHOD
1644:                                || tag == RuntimeConstants.CONSTANT_INTERFACEMETHOD
1645:                                || tag == RuntimeConstants.CONSTANT_NAMEANDTYPE) {
1646:                            out.writeShort(index1);
1647:                        }
1648:                    }
1649:
1650:                    public int hashCode() {
1651:                        return tag + index0 + index1;
1652:                    }
1653:
1654:                    public boolean equals(Object obj) {
1655:                        if (obj instanceof  IndirectEntry) {
1656:                            IndirectEntry other = (IndirectEntry) obj;
1657:                            if (tag == other.tag && index0 == other.index0
1658:                                    && index1 == other.index1) {
1659:                                return true;
1660:                            }
1661:                        }
1662:                        return false;
1663:                    }
1664:                }
1665:            }
1666:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.