Source Code Cross Referenced for ProxyFactory.java in  » Byte-Code » Javassist » javassist » util » proxy » 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 » Byte Code » Javassist » javassist.util.proxy 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Javassist, a Java-bytecode translator toolkit.
0003:         * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
0004:         *
0005:         * The contents of this file are subject to the Mozilla Public License Version
0006:         * 1.1 (the "License"); you may not use this file except in compliance with
0007:         * the License.  Alternatively, the contents of this file may be used under
0008:         * the terms of the GNU Lesser General Public License Version 2.1 or later.
0009:         *
0010:         * Software distributed under the License is distributed on an "AS IS" basis,
0011:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012:         * for the specific language governing rights and limitations under the
0013:         * License.
0014:         */
0015:
0016:        package javassist.util.proxy;
0017:
0018:        import java.lang.reflect.Field;
0019:        import java.lang.reflect.InvocationTargetException;
0020:        import java.lang.reflect.Method;
0021:        import java.lang.reflect.Constructor;
0022:        import java.lang.reflect.Member;
0023:        import java.lang.reflect.Modifier;
0024:        import java.security.ProtectionDomain;
0025:        import java.util.HashMap;
0026:        import java.util.WeakHashMap;
0027:        import java.util.Iterator;
0028:        import java.util.Map;
0029:        import java.util.Set;
0030:        import java.lang.ref.WeakReference;
0031:
0032:        import javassist.CannotCompileException;
0033:        import javassist.bytecode.*;
0034:
0035:        /*
0036:         * This class is implemented only with the lower-level API of Javassist.
0037:         * This design decision is for maximizing performance.
0038:         */
0039:
0040:        /**
0041:         * Factory of dynamic proxy classes.
0042:         *
0043:         * <p>This factory generates a class that extends the given super class and implements
0044:         * the given interfaces.  The calls of the methods inherited from the super class are
0045:         * forwarded and then <code>invoke()</code> is called on the method handler
0046:         * associated with the generated class.  The calls of the methods from the interfaces
0047:         * are also forwarded to the method handler.
0048:         *
0049:         * <p>For example, if the following code is executed,
0050:         * 
0051:         * <ul><pre>
0052:         * ProxyFactory f = new ProxyFactory();
0053:         * f.setSuperclass(Foo.class);
0054:         * MethodHandler mi = new MethodHandler() {
0055:         *     public Object invoke(Object self, Method m, Method proceed,
0056:         *                          Object[] args) throws Throwable {
0057:         *         System.out.println("Name: " + m.getName());
0058:         *         return proceed.invoke(self, args);  // execute the original method.
0059:         *     }
0060:         * };
0061:         * f.setFilter(new MethodFilter() {
0062:         *     public boolean isHandled(Method m) {
0063:         *         // ignore finalize()
0064:         *         return !m.getName().equals("finalize");
0065:         *     }
0066:         * });
0067:         * Class c = f.createClass();
0068:         * Foo foo = (Foo)c.newInstance();
0069:         * ((ProxyObject)foo).setHandler(mi);
0070:         * </pre></ul>
0071:         *
0072:         * <p>Then, the following method call will be forwarded to MethodHandler
0073:         * <code>mi</code> and prints a message before executing the originally called method
0074:         * <code>bar()</code> in <code>Foo</code>.
0075:         *
0076:         * <ul><pre>
0077:         * foo.bar();
0078:         * </pre></ul>
0079:         *
0080:         * <p>The last three lines of the code shown above can be replaced with a call to
0081:         * the helper method <code>create</code>, which generates a proxy class, instantiates
0082:         * it, and sets the method handler of the instance:
0083:         *
0084:         * <ul><pre>
0085:         *     :
0086:         * Foo foo = (Foo)f.create(new Class[0], new Object[0], mi);
0087:         * </pre></ul>
0088:         *
0089:         * <p>To change the method handler during runtime,
0090:         * execute the following code:
0091:         *
0092:         * <ul><pre>
0093:         * MethodHandler mi2 = ... ;    // another handler
0094:         * ((ProxyObject)foo).setHandler(mi2);
0095:         * </pre></ul>
0096:         *
0097:         * <p>You can also specify the default method handler:
0098:         *
0099:         * <ul><pre>
0100:         * ProxyFactory f2 = new ProxyFactory();
0101:         * f2.setSuperclass(Foo.class);
0102:         * f2.setHandler(mi);            // set the default handler
0103:         * Class c2 = f2.createClass();
0104:         * </pre></ul>
0105:         *
0106:         * <p>The default handler is implicitly attached to an instance of the generated class
0107:         * <code>c2</code>.   Calling <code>setHandler</code> on the instance is not necessary
0108:         * unless another method handler must be attached to the instance. 
0109:         *
0110:         * <p>The following code is an example of method handler.  It does not execute
0111:         * anything except invoking the original method:
0112:         *
0113:         * <ul><pre>
0114:         * class SimpleHandler implements MethodHandler {
0115:         *     public Object invoke(Object self, Method m,
0116:         *                          Method proceed, Object[] args) throws Exception {
0117:         *         return proceed.invoke(self, args);
0118:         *     }
0119:         * }
0120:         * </pre></ul>
0121:         *
0122:         * <p>A proxy object generated by <code>ProxyFactory</code> is serializable
0123:         * if its super class or interfaces implement a <code>java.io.Serializable</code>.
0124:         * However, a serialized proxy object will not be compatible with future releases.
0125:         * The serialization support should be used for short-term storage or RMI.
0126:         *
0127:         * @see MethodHandler
0128:         * @since 3.1
0129:         */
0130:        public class ProxyFactory {
0131:            private Class super Class;
0132:            private Class[] interfaces;
0133:            private MethodFilter methodFilter;
0134:            private MethodHandler handler;
0135:            private Class this Class;
0136:
0137:            /**
0138:             * If the value of this variable is not null, the class file of
0139:             * the generated proxy class is written under the directory specified
0140:             * by this variable.  For example, if the value is 
0141:             * <code>"."</code>, then the class file is written under the current
0142:             * directory.  This method is for debugging.
0143:             *
0144:             * <p>The default value is null.
0145:             */
0146:            public String writeDirectory;
0147:
0148:            private static final Class OBJECT_TYPE = Object.class;
0149:
0150:            private static final String HOLDER = "_methods_";
0151:            private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
0152:            private static final String METHOD_FILTER_FIELD = "_method_filter";
0153:            private static final String HANDLER = "handler";
0154:            private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
0155:            private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
0156:            private static final String HANDLER_TYPE = 'L' + MethodHandler.class
0157:                    .getName().replace('.', '/') + ';';
0158:            private static final String HANDLER_SETTER = "setHandler";
0159:            private static final String HANDLER_SETTER_TYPE = "("
0160:                    + HANDLER_TYPE + ")V";
0161:
0162:            /**
0163:             * If true, a generated proxy class is cached and it will be reused
0164:             * when generating the proxy class with the same properties is requested.
0165:             * The default value is true.
0166:             *
0167:             * @since 3.4
0168:             */
0169:            public static boolean useCache = true;
0170:
0171:            private static WeakHashMap proxyCache = new WeakHashMap();
0172:
0173:            static class CacheKey {
0174:                String classes;
0175:                MethodFilter filter;
0176:                private int hash;
0177:                WeakReference proxyClass;
0178:                MethodHandler handler;
0179:
0180:                public CacheKey(Class super Class, Class[] interfaces,
0181:                        MethodFilter f, MethodHandler h) {
0182:                    classes = getKey(super Class, interfaces);
0183:                    hash = classes.hashCode();
0184:                    filter = f;
0185:                    handler = h;
0186:                    proxyClass = null;
0187:                }
0188:
0189:                public int hashCode() {
0190:                    return hash;
0191:                }
0192:
0193:                public boolean equals(Object obj) {
0194:                    if (obj instanceof  CacheKey) {
0195:                        CacheKey target = (CacheKey) obj;
0196:                        return target.filter == filter
0197:                                && target.handler == handler
0198:                                && target.classes.equals(classes);
0199:                    } else
0200:                        return false;
0201:                }
0202:
0203:                static String getKey(Class super Class, Class[] interfaces) {
0204:                    StringBuffer sbuf = new StringBuffer();
0205:                    if (super Class != null)
0206:                        sbuf.append(super Class.getName());
0207:                    sbuf.append(':');
0208:                    if (interfaces != null) {
0209:                        int len = interfaces.length;
0210:                        for (int i = 0; i < len; i++)
0211:                            sbuf.append(interfaces[i].getName()).append(',');
0212:                    }
0213:
0214:                    return sbuf.toString();
0215:                }
0216:            }
0217:
0218:            /**
0219:             * Constructs a factory of proxy class.
0220:             */
0221:            public ProxyFactory() {
0222:                super Class = null;
0223:                interfaces = null;
0224:                methodFilter = null;
0225:                handler = null;
0226:                this Class = null;
0227:                writeDirectory = null;
0228:            }
0229:
0230:            /**
0231:             * Sets the super class of a proxy class.
0232:             */
0233:            public void setSuperclass(Class clazz) {
0234:                super Class = clazz;
0235:            }
0236:
0237:            /**
0238:             * Obtains the super class set by <code>setSuperclass()</code>.
0239:             *
0240:             * @since 3.4
0241:             */
0242:            public Class getSuperclass() {
0243:                return super Class;
0244:            }
0245:
0246:            /**
0247:             * Sets the interfaces of a proxy class.
0248:             */
0249:            public void setInterfaces(Class[] ifs) {
0250:                interfaces = ifs;
0251:            }
0252:
0253:            /**
0254:             * Obtains the interfaces set by <code>setInterfaces</code>.
0255:             *
0256:             * @since 3.4
0257:             */
0258:            public Class[] getInterfaces() {
0259:                return interfaces;
0260:            }
0261:
0262:            /**
0263:             * Sets a filter that selects the methods that will be controlled by a handler.
0264:             */
0265:            public void setFilter(MethodFilter mf) {
0266:                methodFilter = mf;
0267:            }
0268:
0269:            /**
0270:             * Generates a proxy class.
0271:             */
0272:            public Class createClass() {
0273:                if (this Class == null) {
0274:                    ClassLoader cl = getClassLoader();
0275:                    synchronized (proxyCache) {
0276:                        if (useCache)
0277:                            createClass2(cl);
0278:                        else
0279:                            createClass3(cl);
0280:                    }
0281:                }
0282:
0283:                return this Class;
0284:            }
0285:
0286:            private void createClass2(ClassLoader cl) {
0287:                CacheKey key = new CacheKey(super Class, interfaces,
0288:                        methodFilter, handler);
0289:                /*
0290:                 * Excessive concurrency causes a large memory footprint and slows the
0291:                 * execution speed down (with JDK 1.5).  Thus, we use a jumbo lock for
0292:                 * reducing concrrency.
0293:                 */
0294:                // synchronized (proxyCache) {
0295:                HashMap cacheForTheLoader = (HashMap) proxyCache.get(cl);
0296:                if (cacheForTheLoader == null) {
0297:                    cacheForTheLoader = new HashMap();
0298:                    proxyCache.put(cl, cacheForTheLoader);
0299:                    cacheForTheLoader.put(key, key);
0300:                } else {
0301:                    CacheKey found = (CacheKey) cacheForTheLoader.get(key);
0302:                    if (found == null)
0303:                        cacheForTheLoader.put(key, key);
0304:                    else {
0305:                        key = found;
0306:                        Class c = isValidEntry(key); // no need to synchronize
0307:                        if (c != null) {
0308:                            this Class = c;
0309:                            return;
0310:                        }
0311:                    }
0312:                }
0313:                // }
0314:
0315:                // synchronized (key) {
0316:                Class c = isValidEntry(key);
0317:                if (c == null) {
0318:                    createClass3(cl);
0319:                    key.proxyClass = new WeakReference(this Class);
0320:                } else
0321:                    this Class = c;
0322:                // }
0323:            }
0324:
0325:            private Class isValidEntry(CacheKey key) {
0326:                WeakReference ref = key.proxyClass;
0327:                if (ref != null) {
0328:                    Class c = (Class) ref.get();
0329:                    if (c != null)
0330:                        return c;
0331:                }
0332:
0333:                return null;
0334:            }
0335:
0336:            private void createClass3(ClassLoader cl) {
0337:                try {
0338:                    ClassFile cf = make();
0339:                    if (writeDirectory != null)
0340:                        FactoryHelper.writeFile(cf, writeDirectory);
0341:
0342:                    this Class = FactoryHelper.toClass(cf, cl, getDomain());
0343:                    setField(DEFAULT_INTERCEPTOR, handler);
0344:                    setField(METHOD_FILTER_FIELD, methodFilter);
0345:                } catch (CannotCompileException e) {
0346:                    throw new RuntimeException(e.getMessage(), e);
0347:                }
0348:
0349:            }
0350:
0351:            private void setField(String fieldName, Object value) {
0352:                if (this Class != null && value != null)
0353:                    try {
0354:                        Field f = this Class.getField(fieldName);
0355:                        f.setAccessible(true);
0356:                        f.set(null, value);
0357:                        f.setAccessible(false);
0358:                    } catch (Exception e) {
0359:                        throw new RuntimeException(e);
0360:                    }
0361:            }
0362:
0363:            static MethodFilter getFilter(Class clazz) {
0364:                return (MethodFilter) getField(clazz, METHOD_FILTER_FIELD);
0365:            }
0366:
0367:            static MethodHandler getHandler(Class clazz) {
0368:                return (MethodHandler) getField(clazz, DEFAULT_INTERCEPTOR);
0369:            }
0370:
0371:            private static Object getField(Class clazz, String fieldName) {
0372:                try {
0373:                    Field f = clazz.getField(fieldName);
0374:                    f.setAccessible(true);
0375:                    Object value = f.get(null);
0376:                    f.setAccessible(false);
0377:                    return value;
0378:                } catch (Exception e) {
0379:                    throw new RuntimeException(e);
0380:                }
0381:            }
0382:
0383:            /**
0384:             * A provider of class loaders.
0385:             *
0386:             * @see #classLoaderProvider
0387:             * @since 3.4
0388:             */
0389:            public static interface ClassLoaderProvider {
0390:                /**
0391:                 * Returns a class loader.
0392:                 *
0393:                 * @param pf    a proxy factory that is going to obtain a class loader.
0394:                 */
0395:                public ClassLoader get(ProxyFactory pf);
0396:            }
0397:
0398:            /**
0399:             * A provider used by <code>createClass()</code> for obtaining
0400:             * a class loader.
0401:             * <code>get()</code> on this <code>ClassLoaderProvider</code> object
0402:             * is called to obtain a class loader.
0403:             *
0404:             * <p>The value of this field can be updated for changing the default
0405:             * implementation.
0406:             *
0407:             * <p>Example:
0408:             * <ul><pre>
0409:             * ProxyFactory.classLoaderProvider = new ProxyFactory.ClassLoaderProvider() {
0410:             *     public ClassLoader get(ProxyFactory pf) {
0411:             *         return Thread.currentThread().getContextClassLoader();
0412:             *     }
0413:             * };
0414:             * </pre></ul>
0415:             *
0416:             * @since 3.4
0417:             */
0418:            public static ClassLoaderProvider classLoaderProvider = new ClassLoaderProvider() {
0419:                public ClassLoader get(ProxyFactory pf) {
0420:                    return pf.getClassLoader0();
0421:                }
0422:            };
0423:
0424:            protected ClassLoader getClassLoader() {
0425:                return classLoaderProvider.get(this );
0426:            }
0427:
0428:            protected ClassLoader getClassLoader0() {
0429:                ClassLoader loader = null;
0430:                if (super Class != null
0431:                        && !super Class.getName().equals("java.lang.Object"))
0432:                    loader = super Class.getClassLoader();
0433:                else if (interfaces != null && interfaces.length > 0)
0434:                    loader = interfaces[0].getClassLoader();
0435:
0436:                if (loader == null) {
0437:                    loader = getClass().getClassLoader();
0438:                    // In case javassist is in the endorsed dir
0439:                    if (loader == null) {
0440:                        loader = Thread.currentThread().getContextClassLoader();
0441:                        if (loader == null)
0442:                            loader = ClassLoader.getSystemClassLoader();
0443:                    }
0444:                }
0445:
0446:                return loader;
0447:            }
0448:
0449:            protected ProtectionDomain getDomain() {
0450:                Class clazz;
0451:                if (super Class != null
0452:                        && !super Class.getName().equals("java.lang.Object"))
0453:                    clazz = super Class;
0454:                else if (interfaces != null && interfaces.length > 0)
0455:                    clazz = interfaces[0];
0456:                else
0457:                    clazz = this .getClass();
0458:
0459:                return clazz.getProtectionDomain();
0460:            }
0461:
0462:            /**
0463:             * Creates a proxy class and returns an instance of that class.
0464:             *
0465:             * @param paramTypes    parameter types for a constructor.
0466:             * @param args          arguments passed to a constructor.
0467:             * @param mh            the method handler for the proxy class.
0468:             * @since 3.4
0469:             */
0470:            public Object create(Class[] paramTypes, Object[] args,
0471:                    MethodHandler mh) throws NoSuchMethodException,
0472:                    IllegalArgumentException, InstantiationException,
0473:                    IllegalAccessException, InvocationTargetException {
0474:                Object obj = create(paramTypes, args);
0475:                ((ProxyObject) obj).setHandler(mh);
0476:                return obj;
0477:            }
0478:
0479:            /**
0480:             * Creates a proxy class and returns an instance of that class.
0481:             *
0482:             * @param paramTypes    parameter types for a constructor.
0483:             * @param args          arguments passed to a constructor.
0484:             */
0485:            public Object create(Class[] paramTypes, Object[] args)
0486:                    throws NoSuchMethodException, IllegalArgumentException,
0487:                    InstantiationException, IllegalAccessException,
0488:                    InvocationTargetException {
0489:                Class c = createClass();
0490:                Constructor cons = c.getConstructor(paramTypes);
0491:                return cons.newInstance(args);
0492:            }
0493:
0494:            /**
0495:             * Sets the default invocation handler.  This invocation handler is shared
0496:             * among all the instances of a proxy class unless another is explicitly
0497:             * specified.
0498:             */
0499:            public void setHandler(MethodHandler mi) {
0500:                handler = mi;
0501:                setField(DEFAULT_INTERCEPTOR, handler);
0502:            }
0503:
0504:            private static int counter = 0;
0505:
0506:            private static synchronized String makeProxyName(String classname) {
0507:                return classname + "_$$_javassist_" + counter++;
0508:            }
0509:
0510:            private ClassFile make() throws CannotCompileException {
0511:                String super Name, classname;
0512:                if (interfaces == null)
0513:                    interfaces = new Class[0];
0514:
0515:                if (super Class == null) {
0516:                    super Class = OBJECT_TYPE;
0517:                    super Name = super Class.getName();
0518:                    classname = interfaces.length == 0 ? super Name
0519:                            : interfaces[0].getName();
0520:                } else {
0521:                    super Name = super Class.getName();
0522:                    classname = super Name;
0523:                }
0524:
0525:                if (Modifier.isFinal(super Class.getModifiers()))
0526:                    throw new CannotCompileException(super Name + " is final");
0527:
0528:                classname = makeProxyName(classname);
0529:                if (classname.startsWith("java."))
0530:                    classname = "org.javassist.tmp." + classname;
0531:
0532:                ClassFile cf = new ClassFile(false, classname, super Name);
0533:                cf.setAccessFlags(AccessFlag.PUBLIC);
0534:                setInterfaces(cf, interfaces);
0535:                ConstPool pool = cf.getConstPool();
0536:                FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR,
0537:                        HANDLER_TYPE);
0538:                finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
0539:                cf.addField(finfo);
0540:
0541:                FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);
0542:                finfo2.setAccessFlags(AccessFlag.PRIVATE);
0543:                cf.addField(finfo2);
0544:
0545:                FieldInfo finfo3 = new FieldInfo(pool, METHOD_FILTER_FIELD,
0546:                        "Ljavassist/util/proxy/MethodFilter;");
0547:                finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
0548:                cf.addField(finfo3);
0549:
0550:                HashMap allMethods = getMethods(super Class, interfaces);
0551:                int size = allMethods.size();
0552:                makeConstructors(classname, cf, pool, classname);
0553:                int s = overrideMethods(cf, pool, classname, allMethods);
0554:                addMethodsHolder(cf, pool, classname, s);
0555:                addSetter(classname, cf, pool);
0556:
0557:                try {
0558:                    cf.addMethod(makeWriteReplace(pool));
0559:                } catch (DuplicateMemberException e) {
0560:                    // writeReplace() is already declared in the super class/interfaces.
0561:                }
0562:
0563:                this Class = null;
0564:                return cf;
0565:            }
0566:
0567:            private static void setInterfaces(ClassFile cf, Class[] interfaces) {
0568:                String setterIntf = ProxyObject.class.getName();
0569:                String[] list;
0570:                if (interfaces == null || interfaces.length == 0)
0571:                    list = new String[] { setterIntf };
0572:                else {
0573:                    list = new String[interfaces.length + 1];
0574:                    for (int i = 0; i < interfaces.length; i++)
0575:                        list[i] = interfaces[i].getName();
0576:
0577:                    list[interfaces.length] = setterIntf;
0578:                }
0579:
0580:                cf.setInterfaces(list);
0581:            }
0582:
0583:            private static void addMethodsHolder(ClassFile cf, ConstPool cp,
0584:                    String classname, int size) throws CannotCompileException {
0585:                FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
0586:                finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
0587:                cf.addField(finfo);
0588:                MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
0589:                Bytecode code = new Bytecode(cp, 0, 0);
0590:                code.addIconst(size * 2);
0591:                code.addAnewarray("java.lang.reflect.Method");
0592:                code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
0593:                code.addOpcode(Bytecode.RETURN);
0594:                minfo.setCodeAttribute(code.toCodeAttribute());
0595:                cf.addMethod(minfo);
0596:            }
0597:
0598:            private static void addSetter(String classname, ClassFile cf,
0599:                    ConstPool cp) throws CannotCompileException {
0600:                MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,
0601:                        HANDLER_SETTER_TYPE);
0602:                minfo.setAccessFlags(AccessFlag.PUBLIC);
0603:                Bytecode code = new Bytecode(cp, 2, 2);
0604:                code.addAload(0);
0605:                code.addAload(1);
0606:                code.addPutfield(classname, HANDLER, HANDLER_TYPE);
0607:                code.addOpcode(Bytecode.RETURN);
0608:                minfo.setCodeAttribute(code.toCodeAttribute());
0609:                cf.addMethod(minfo);
0610:            }
0611:
0612:            private int overrideMethods(ClassFile cf, ConstPool cp,
0613:                    String className, HashMap allMethods)
0614:                    throws CannotCompileException {
0615:                String prefix = makeUniqueName("_d", allMethods);
0616:                Set entries = allMethods.entrySet();
0617:                Iterator it = entries.iterator();
0618:                int index = 0;
0619:                while (it.hasNext()) {
0620:                    Map.Entry e = (Map.Entry) it.next();
0621:                    String key = (String) e.getKey();
0622:                    Method meth = (Method) e.getValue();
0623:                    int mod = meth.getModifiers();
0624:                    if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)
0625:                            && isVisible(mod, className, meth))
0626:                        if (methodFilter == null
0627:                                || methodFilter.isHandled(meth))
0628:                            override(className, meth, prefix, index++,
0629:                                    keyToDesc(key), cf, cp);
0630:                }
0631:
0632:                return index;
0633:            }
0634:
0635:            private void override(String this Classname, Method meth,
0636:                    String prefix, int index, String desc, ClassFile cf,
0637:                    ConstPool cp) throws CannotCompileException {
0638:                Class declClass = meth.getDeclaringClass();
0639:                String delegatorName = prefix + index + meth.getName();
0640:                if (Modifier.isAbstract(meth.getModifiers()))
0641:                    delegatorName = null;
0642:                else {
0643:                    MethodInfo delegator = makeDelegator(meth, desc, cp,
0644:                            declClass, delegatorName);
0645:                    // delegator is not a bridge method.  See Sec. 15.12.4.5 of JLS 3rd Ed.
0646:                    delegator.setAccessFlags(delegator.getAccessFlags()
0647:                            & ~AccessFlag.BRIDGE);
0648:                    cf.addMethod(delegator);
0649:                }
0650:
0651:                MethodInfo forwarder = makeForwarder(this Classname, meth, desc,
0652:                        cp, declClass, delegatorName, index);
0653:                cf.addMethod(forwarder);
0654:            }
0655:
0656:            private void makeConstructors(String this ClassName, ClassFile cf,
0657:                    ConstPool cp, String classname)
0658:                    throws CannotCompileException {
0659:                Constructor[] cons = super Class.getDeclaredConstructors();
0660:                for (int i = 0; i < cons.length; i++) {
0661:                    Constructor c = cons[i];
0662:                    int mod = c.getModifiers();
0663:                    if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)
0664:                            && isVisible(mod, classname, c)) {
0665:                        MethodInfo m = makeConstructor(this ClassName, c, cp,
0666:                                super Class);
0667:                        cf.addMethod(m);
0668:                    }
0669:                }
0670:            }
0671:
0672:            private static String makeUniqueName(String name, HashMap hash) {
0673:                Set keys = hash.keySet();
0674:                if (makeUniqueName0(name, keys.iterator()))
0675:                    return name;
0676:
0677:                for (int i = 100; i < 999; i++) {
0678:                    String s = name + i;
0679:                    if (makeUniqueName0(s, keys.iterator()))
0680:                        return s;
0681:                }
0682:
0683:                throw new RuntimeException("cannot make a unique method name");
0684:            }
0685:
0686:            private static boolean makeUniqueName0(String name, Iterator it) {
0687:                while (it.hasNext()) {
0688:                    String key = (String) it.next();
0689:                    if (key.startsWith(name))
0690:                        return false;
0691:                }
0692:
0693:                return true;
0694:            }
0695:
0696:            /**
0697:             * Returns true if the method is visible from the class.
0698:             *
0699:             * @param mod       the modifiers of the method. 
0700:             */
0701:            private static boolean isVisible(int mod, String from, Member meth) {
0702:                if ((mod & Modifier.PRIVATE) != 0)
0703:                    return false;
0704:                else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
0705:                    return true;
0706:                else {
0707:                    String p = getPackageName(from);
0708:                    String q = getPackageName(meth.getDeclaringClass()
0709:                            .getName());
0710:                    if (p == null)
0711:                        return q == null;
0712:                    else
0713:                        return p.equals(q);
0714:                }
0715:            }
0716:
0717:            private static String getPackageName(String name) {
0718:                int i = name.lastIndexOf('.');
0719:                if (i < 0)
0720:                    return null;
0721:                else
0722:                    return name.substring(0, i);
0723:            }
0724:
0725:            private static HashMap getMethods(Class super Class,
0726:                    Class[] interfaceTypes) {
0727:                HashMap hash = new HashMap();
0728:                for (int i = 0; i < interfaceTypes.length; i++)
0729:                    getMethods(hash, interfaceTypes[i]);
0730:
0731:                getMethods(hash, super Class);
0732:                return hash;
0733:            }
0734:
0735:            private static void getMethods(HashMap hash, Class clazz) {
0736:                Class[] ifs = clazz.getInterfaces();
0737:                for (int i = 0; i < ifs.length; i++)
0738:                    getMethods(hash, ifs[i]);
0739:
0740:                Class parent = clazz.getSuperclass();
0741:                if (parent != null)
0742:                    getMethods(hash, parent);
0743:
0744:                Method[] methods = clazz.getDeclaredMethods();
0745:                for (int i = 0; i < methods.length; i++)
0746:                    if (!Modifier.isPrivate(methods[i].getModifiers())) {
0747:                        Method m = methods[i];
0748:                        String key = m.getName() + ':'
0749:                                + RuntimeSupport.makeDescriptor(m);
0750:                        hash.put(key, methods[i]);
0751:                    }
0752:            }
0753:
0754:            private static String keyToDesc(String key) {
0755:                return key.substring(key.indexOf(':') + 1);
0756:            }
0757:
0758:            private static MethodInfo makeConstructor(String this ClassName,
0759:                    Constructor cons, ConstPool cp, Class super Class) {
0760:                String desc = RuntimeSupport.makeDescriptor(cons
0761:                        .getParameterTypes(), Void.TYPE);
0762:                MethodInfo minfo = new MethodInfo(cp, "<init>", desc);
0763:                minfo.setAccessFlags(Modifier.PUBLIC); // cons.getModifiers() & ~Modifier.NATIVE
0764:                setThrows(minfo, cp, cons.getExceptionTypes());
0765:                Bytecode code = new Bytecode(cp, 0, 0);
0766:
0767:                code.addAload(0);
0768:                code.addGetstatic(this ClassName, DEFAULT_INTERCEPTOR,
0769:                        HANDLER_TYPE);
0770:                code.addOpcode(Opcode.DUP);
0771:                code.addOpcode(Opcode.IFNONNULL);
0772:                code.addIndex(7);
0773:                code.addOpcode(Opcode.POP);
0774:                code.addGetstatic(NULL_INTERCEPTOR_HOLDER, DEFAULT_INTERCEPTOR,
0775:                        HANDLER_TYPE);
0776:                code.addPutfield(this ClassName, HANDLER, HANDLER_TYPE);
0777:
0778:                code.addAload(0);
0779:                int s = addLoadParameters(code, cons.getParameterTypes(), 1);
0780:                code.addInvokespecial(super Class.getName(), "<init>", desc);
0781:                code.addOpcode(Opcode.RETURN);
0782:                code.setMaxLocals(s + 1);
0783:                minfo.setCodeAttribute(code.toCodeAttribute());
0784:                return minfo;
0785:            }
0786:
0787:            private static MethodInfo makeDelegator(Method meth, String desc,
0788:                    ConstPool cp, Class declClass, String delegatorName) {
0789:                MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
0790:                delegator.setAccessFlags(Modifier.FINAL
0791:                        | Modifier.PUBLIC
0792:                        | (meth.getModifiers() & ~(Modifier.PRIVATE
0793:                                | Modifier.PROTECTED | Modifier.ABSTRACT
0794:                                | Modifier.NATIVE | Modifier.SYNCHRONIZED)));
0795:                setThrows(delegator, cp, meth);
0796:                Bytecode code = new Bytecode(cp, 0, 0);
0797:                code.addAload(0);
0798:                int s = addLoadParameters(code, meth.getParameterTypes(), 1);
0799:                code
0800:                        .addInvokespecial(declClass.getName(), meth.getName(),
0801:                                desc);
0802:                addReturn(code, meth.getReturnType());
0803:                code.setMaxLocals(++s);
0804:                delegator.setCodeAttribute(code.toCodeAttribute());
0805:                return delegator;
0806:            }
0807:
0808:            /**
0809:             * @param delegatorName     null if the original method is abstract.
0810:             */
0811:            private static MethodInfo makeForwarder(String this ClassName,
0812:                    Method meth, String desc, ConstPool cp, Class declClass,
0813:                    String delegatorName, int index) {
0814:                MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
0815:                forwarder.setAccessFlags(Modifier.FINAL
0816:                        | (meth.getModifiers() & ~(Modifier.ABSTRACT
0817:                                | Modifier.NATIVE | Modifier.SYNCHRONIZED)));
0818:                setThrows(forwarder, cp, meth);
0819:                int args = Descriptor.paramSize(desc);
0820:                Bytecode code = new Bytecode(cp, 0, args + 2);
0821:                /*
0822:                 * if (methods[index * 2] == null) {
0823:                 *   methods[index * 2]
0824:                 *     = RuntimeSupport.findMethod(this, <overridden name>, <desc>);
0825:                 *   methods[index * 2 + 1]
0826:                 *     = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
0827:                 *     or = null // the original method is abstract.
0828:                 * }
0829:                 * return ($r)handler.invoke(this, methods[index * 2],
0830:                 *                methods[index * 2 + 1], $args);
0831:                 */
0832:                int origIndex = index * 2;
0833:                int delIndex = index * 2 + 1;
0834:                int arrayVar = args + 1;
0835:                code.addGetstatic(this ClassName, HOLDER, HOLDER_TYPE);
0836:                code.addAstore(arrayVar);
0837:                code.addAload(arrayVar);
0838:                code.addIconst(origIndex);
0839:                code.addOpcode(Opcode.AALOAD);
0840:                code.addOpcode(Opcode.IFNONNULL);
0841:                int pc = code.currentPc();
0842:                code.addIndex(0);
0843:
0844:                callFindMethod(code, "findSuperMethod", arrayVar, origIndex,
0845:                        meth.getName(), desc);
0846:                callFindMethod(code, "findMethod", arrayVar, delIndex,
0847:                        delegatorName, desc);
0848:
0849:                code.write16bit(pc, code.currentPc() - pc + 1);
0850:                code.addAload(0);
0851:                code.addGetfield(this ClassName, HANDLER, HANDLER_TYPE);
0852:                code.addAload(0);
0853:
0854:                code.addAload(arrayVar);
0855:                code.addIconst(origIndex);
0856:                code.addOpcode(Opcode.AALOAD);
0857:
0858:                code.addAload(arrayVar);
0859:                code.addIconst(delIndex);
0860:                code.addOpcode(Opcode.AALOAD);
0861:
0862:                makeParameterList(code, meth.getParameterTypes());
0863:                code
0864:                        .addInvokeinterface(
0865:                                MethodHandler.class.getName(),
0866:                                "invoke",
0867:                                "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
0868:                                5);
0869:                Class retType = meth.getReturnType();
0870:                addUnwrapper(code, retType);
0871:                addReturn(code, retType);
0872:
0873:                forwarder.setCodeAttribute(code.toCodeAttribute());
0874:                return forwarder;
0875:            }
0876:
0877:            private static void setThrows(MethodInfo minfo, ConstPool cp,
0878:                    Method orig) {
0879:                Class[] exceptions = orig.getExceptionTypes();
0880:                setThrows(minfo, cp, exceptions);
0881:            }
0882:
0883:            private static void setThrows(MethodInfo minfo, ConstPool cp,
0884:                    Class[] exceptions) {
0885:                if (exceptions.length == 0)
0886:                    return;
0887:
0888:                String[] list = new String[exceptions.length];
0889:                for (int i = 0; i < exceptions.length; i++)
0890:                    list[i] = exceptions[i].getName();
0891:
0892:                ExceptionsAttribute ea = new ExceptionsAttribute(cp);
0893:                ea.setExceptions(list);
0894:                minfo.setExceptionsAttribute(ea);
0895:            }
0896:
0897:            private static int addLoadParameters(Bytecode code, Class[] params,
0898:                    int offset) {
0899:                int stacksize = 0;
0900:                int n = params.length;
0901:                for (int i = 0; i < n; ++i)
0902:                    stacksize += addLoad(code, stacksize + offset, params[i]);
0903:
0904:                return stacksize;
0905:            }
0906:
0907:            private static int addLoad(Bytecode code, int n, Class type) {
0908:                if (type.isPrimitive()) {
0909:                    if (type == Long.TYPE) {
0910:                        code.addLload(n);
0911:                        return 2;
0912:                    } else if (type == Float.TYPE)
0913:                        code.addFload(n);
0914:                    else if (type == Double.TYPE) {
0915:                        code.addDload(n);
0916:                        return 2;
0917:                    } else
0918:                        code.addIload(n);
0919:                } else
0920:                    code.addAload(n);
0921:
0922:                return 1;
0923:            }
0924:
0925:            private static int addReturn(Bytecode code, Class type) {
0926:                if (type.isPrimitive()) {
0927:                    if (type == Long.TYPE) {
0928:                        code.addOpcode(Opcode.LRETURN);
0929:                        return 2;
0930:                    } else if (type == Float.TYPE)
0931:                        code.addOpcode(Opcode.FRETURN);
0932:                    else if (type == Double.TYPE) {
0933:                        code.addOpcode(Opcode.DRETURN);
0934:                        return 2;
0935:                    } else if (type == Void.TYPE) {
0936:                        code.addOpcode(Opcode.RETURN);
0937:                        return 0;
0938:                    } else
0939:                        code.addOpcode(Opcode.IRETURN);
0940:                } else
0941:                    code.addOpcode(Opcode.ARETURN);
0942:
0943:                return 1;
0944:            }
0945:
0946:            private static void makeParameterList(Bytecode code, Class[] params) {
0947:                int regno = 1;
0948:                int n = params.length;
0949:                code.addIconst(n);
0950:                code.addAnewarray("java/lang/Object");
0951:                for (int i = 0; i < n; i++) {
0952:                    code.addOpcode(Opcode.DUP);
0953:                    code.addIconst(i);
0954:                    Class type = params[i];
0955:                    if (type.isPrimitive())
0956:                        regno = makeWrapper(code, type, regno);
0957:                    else {
0958:                        code.addAload(regno);
0959:                        regno++;
0960:                    }
0961:
0962:                    code.addOpcode(Opcode.AASTORE);
0963:                }
0964:            }
0965:
0966:            private static int makeWrapper(Bytecode code, Class type, int regno) {
0967:                int index = FactoryHelper.typeIndex(type);
0968:                String wrapper = FactoryHelper.wrapperTypes[index];
0969:                code.addNew(wrapper);
0970:                code.addOpcode(Opcode.DUP);
0971:                addLoad(code, regno, type);
0972:                code.addInvokespecial(wrapper, "<init>",
0973:                        FactoryHelper.wrapperDesc[index]);
0974:                return regno + FactoryHelper.dataSize[index];
0975:            }
0976:
0977:            /**
0978:             * @param methodName        might be null.
0979:             */
0980:            private static void callFindMethod(Bytecode code,
0981:                    String findMethod, int arrayVar, int index,
0982:                    String methodName, String desc) {
0983:                String findClass = RuntimeSupport.class.getName();
0984:                String findDesc = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Method;";
0985:
0986:                code.addAload(arrayVar);
0987:                code.addIconst(index);
0988:                if (methodName == null)
0989:                    code.addOpcode(Opcode.ACONST_NULL);
0990:                else {
0991:                    code.addAload(0);
0992:                    code.addLdc(methodName);
0993:                    code.addLdc(desc);
0994:                    code.addInvokestatic(findClass, findMethod, findDesc);
0995:                }
0996:
0997:                code.addOpcode(Opcode.AASTORE);
0998:            }
0999:
1000:            private static void addUnwrapper(Bytecode code, Class type) {
1001:                if (type.isPrimitive()) {
1002:                    if (type == Void.TYPE)
1003:                        code.addOpcode(Opcode.POP);
1004:                    else {
1005:                        int index = FactoryHelper.typeIndex(type);
1006:                        String wrapper = FactoryHelper.wrapperTypes[index];
1007:                        code.addCheckcast(wrapper);
1008:                        code.addInvokevirtual(wrapper,
1009:                                FactoryHelper.unwarpMethods[index],
1010:                                FactoryHelper.unwrapDesc[index]);
1011:                    }
1012:                } else
1013:                    code.addCheckcast(type.getName());
1014:            }
1015:
1016:            private static MethodInfo makeWriteReplace(ConstPool cp) {
1017:                MethodInfo minfo = new MethodInfo(cp, "writeReplace",
1018:                        "()Ljava/lang/Object;");
1019:                String[] list = new String[1];
1020:                list[0] = "java.io.ObjectStreamException";
1021:                ExceptionsAttribute ea = new ExceptionsAttribute(cp);
1022:                ea.setExceptions(list);
1023:                minfo.setExceptionsAttribute(ea);
1024:                Bytecode code = new Bytecode(cp, 0, 1);
1025:                code.addAload(0);
1026:                code
1027:                        .addInvokestatic("javassist.util.proxy.RuntimeSupport",
1028:                                "makeSerializedProxy",
1029:                                "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
1030:                code.addOpcode(Opcode.ARETURN);
1031:                minfo.setCodeAttribute(code.toCodeAttribute());
1032:                return minfo;
1033:            }
1034:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.