[jboss-cvs] javassist/src/main/javassist/util/proxy ...

Shigeru Chiba chiba at is.titech.ac.jp
Sun Nov 5 18:16:35 EST 2006


  User: chiba   
  Date: 06/11/05 18:16:35

  Modified:    src/main/javassist/util/proxy    ProxyFactory.java
                        RuntimeSupport.java
  Added:       src/main/javassist/util/proxy    SerializedProxy.java
  Log:
  made a proxy class serializable (JASSIST-20).
  
  Revision  Changes    Path
  1.20      +89 -38    javassist/src/main/javassist/util/proxy/ProxyFactory.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: ProxyFactory.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/util/proxy/ProxyFactory.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -b -r1.19 -r1.20
  --- ProxyFactory.java	2 Nov 2006 14:30:22 -0000	1.19
  +++ ProxyFactory.java	5 Nov 2006 23:16:35 -0000	1.20
  @@ -32,6 +32,11 @@
   import javassist.CannotCompileException;
   import javassist.bytecode.*;
   
  +/*
  + * This class is implemented only with the lower-level API of Javassist.
  + * This design decision is for maximizing performance.
  + */
  +
   /**
    * Factory of dynamic proxy classes.
    *
  @@ -92,6 +97,11 @@
    * }
    * </pre></ul>
    *
  + * <p>A proxy object generated by <code>ProxyFactory</code> is serializable
  + * if its super class or interfaces implement a <code>java.io.Serializable</code>.
  + * However, a serialized proxy object will not be compatible with future releases.
  + * The serialization support should be used for short-term storage or RMI.
  + *
    * @see MethodHandler
    * @since 3.1
    */
  @@ -117,6 +127,7 @@
   
       private static final String HOLDER = "_methods_";
       private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
  +    private static final String METHOD_FILTER_FIELD = "_method_filter";
       private static final String HANDLER = "handler";
       private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
       private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
  @@ -137,8 +148,8 @@
       private static WeakHashMap proxyCache = new WeakHashMap();
   
       static class CacheKey {
  -        private String classes;
  -        private MethodFilter filter;
  +        String classes;
  +        MethodFilter filter;
           private int hash;
           WeakReference proxyClass;
           MethodHandler handler;
  @@ -233,18 +244,25 @@
       public Class createClass() {
           if (thisClass == null) {
               ClassLoader cl = getClassLoader();
  +            synchronized (proxyCache) {
               if (useCache)
                   createClass2(cl);
               else
                   createClass3(cl);
           }
  +        }
   
           return thisClass;
       }
   
       private void createClass2(ClassLoader cl) {
           CacheKey key = new CacheKey(superClass, interfaces, methodFilter, handler);
  -        synchronized (proxyCache) {
  +        /*
  +         * Excessive concurrency causes a large memory footprint and slows the
  +         * execution speed down (with JDK 1.5).  Thus, we use a jumbo lock for
  +         * reducing concrrency.
  +         */
  +        // synchronized (proxyCache) {
               HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
               if (cacheForTheLoader == null) {
                   cacheForTheLoader = new HashMap();
  @@ -264,9 +282,9 @@
                       }
                   }
               }
  -        }
  +        // }
   
  -        synchronized (key) {
  +        // synchronized (key) {
               Class c = isValidEntry(key);
               if (c == null) {
                   createClass3(cl);
  @@ -274,7 +292,7 @@
               }
               else
                   thisClass = c; 
  -        }
  +        // }
       }
   
       private Class isValidEntry(CacheKey key) {
  @@ -295,7 +313,8 @@
                   FactoryHelper.writeFile(cf, writeDirectory);
   
               thisClass = FactoryHelper.toClass(cf, cl, getDomain());
  -            setHandler();
  +            setField(DEFAULT_INTERCEPTOR, handler);
  +            setField(METHOD_FILTER_FIELD, methodFilter);
           }
           catch (CannotCompileException e) {
               throw new RuntimeException(e.getMessage(), e);
  @@ -303,6 +322,40 @@
   
       }
   
  +    private void setField(String fieldName, Object value) {
  +        if (thisClass != null && value != null)
  +            try {
  +                Field f = thisClass.getField(fieldName);
  +                f.setAccessible(true);
  +                f.set(null, value);
  +                f.setAccessible(false);
  +            }
  +            catch (Exception e) {
  +                throw new RuntimeException(e);
  +            }
  +    }
  +
  +    static MethodFilter getFilter(Class clazz) {
  +        return (MethodFilter)getField(clazz, METHOD_FILTER_FIELD);
  +    }
  +
  +    static MethodHandler getHandler(Class clazz) {
  +        return (MethodHandler)getField(clazz, DEFAULT_INTERCEPTOR);
  +    }
  +
  +    private static Object getField(Class clazz, String fieldName) {
  +        try {
  +            Field f = clazz.getField(fieldName);
  +            f.setAccessible(true);
  +            Object value = f.get(null);
  +            f.setAccessible(false);
  +            return value;
  +        }
  +        catch (Exception e) {
  +            throw new RuntimeException(e);
  +        }
  +    }
  +
       /**
        * A provider of class loaders.
        *
  @@ -403,33 +456,7 @@
        */
       public void setHandler(MethodHandler mi) {
           handler = mi;
  -        setHandler();
  -    }
  -
  -    private void setHandler() {
  -        if (thisClass != null && handler != null)
  -            try {
  -                Field f = thisClass.getField(DEFAULT_INTERCEPTOR);
  -                f.setAccessible(true);
  -                f.set(null, handler);
  -                f.setAccessible(false);
  -            }
  -            catch (Exception e) {
  -                throw new RuntimeException(e);
  -            }
  -    }
  -
  -    static MethodHandler getHandler(Class clazz) {
  -        try {
  -            Field f = clazz.getField(DEFAULT_INTERCEPTOR);
  -            f.setAccessible(true);
  -            MethodHandler h = (MethodHandler)f.get(null);
  -            f.setAccessible(false);
  -            return h;
  -        }
  -        catch (Exception e) {
  -            throw new RuntimeException(e);
  -        }
  +        setField(DEFAULT_INTERCEPTOR, handler);
       }
   
       private static int counter = 0;
  @@ -473,6 +500,11 @@
           finfo2.setAccessFlags(AccessFlag.PRIVATE);
           cf.addField(finfo2);
   
  +        FieldInfo finfo3 = new FieldInfo(pool, METHOD_FILTER_FIELD,
  +                                            "Ljavassist/util/proxy/MethodFilter;");
  +        finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
  +        cf.addField(finfo3);
  +
           HashMap allMethods = getMethods(superClass, interfaces);
           int size = allMethods.size();
           makeConstructors(classname, cf, pool, classname);
  @@ -480,6 +512,8 @@
           addMethodsHolder(cf, pool, classname, s);
           addSetter(classname, cf, pool);
   
  +        cf.addMethod(makeWriteReplace(pool));
  +
           thisClass = null;          
           return cf;
       }
  @@ -932,4 +966,21 @@
           else
               code.addCheckcast(type.getName());
       }
  +
  +    private static MethodInfo makeWriteReplace(ConstPool cp) {
  +        MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
  +        String[] list = new String[1];
  +        list[0] = "java.io.ObjectStreamException";
  +        ExceptionsAttribute ea = new ExceptionsAttribute(cp);
  +        ea.setExceptions(list);
  +        minfo.setExceptionsAttribute(ea);
  +        Bytecode code = new Bytecode(cp, 0, 1);
  +        code.addAload(0);
  +        code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
  +                             "makeSerializedProxy",
  +                             "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
  +        code.addOpcode(Opcode.ARETURN);
  +        minfo.setCodeAttribute(code.toCodeAttribute());
  +        return minfo;
  +    }
   }
  
  
  
  1.4       +19 -1     javassist/src/main/javassist/util/proxy/RuntimeSupport.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: RuntimeSupport.java
  ===================================================================
  RCS file: /cvsroot/jboss/javassist/src/main/javassist/util/proxy/RuntimeSupport.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -b -r1.3 -r1.4
  --- RuntimeSupport.java	14 Feb 2006 04:27:38 -0000	1.3
  +++ RuntimeSupport.java	5 Nov 2006 23:16:35 -0000	1.4
  @@ -16,6 +16,7 @@
   package javassist.util.proxy;
   
   import java.lang.reflect.Method;
  +import java.io.Serializable;
   
   /**
    * Runtime support routines that the classes generated by ProxyFactory use.
  @@ -26,7 +27,9 @@
       /**
        * A method handler that only executes a method.
        */
  -    public static MethodHandler default_interceptor = new MethodHandler() {
  +    public static MethodHandler default_interceptor = new DefaultMethodHandler();
  +
  +    static class DefaultMethodHandler implements MethodHandler, Serializable {
           public Object invoke(Object self, Method m,
                                Method proceed, Object[] args)
               throws Exception
  @@ -166,4 +169,19 @@
               sbuf.append('L').append(type.getName().replace('.', '/'))
                   .append(';');
       }
  +
  +    /**
  +     * Converts a proxy object to an object that is writable to an
  +     * object stream.  This method is called by <code>writeReplace()</code>
  +     * in a proxy class.
  +     *
  +     * @since 3.4
  +     */
  +    public static SerializedProxy makeSerializedProxy(Object proxy)
  +        throws java.io.InvalidClassException
  +    {
  +        Class clazz = proxy.getClass();
  +        return new SerializedProxy(clazz, ProxyFactory.getFilter(clazz),
  +                                   ProxyFactory.getHandler(clazz));
  +    }
   }
  
  
  
  1.1      date: 2006/11/05 23:16:35;  author: chiba;  state: Exp;javassist/src/main/javassist/util/proxy/SerializedProxy.java
  
  Index: SerializedProxy.java
  ===================================================================
  /*
   * Javassist, a Java-bytecode translator toolkit.
   * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
   *
   * The contents of this file are subject to the Mozilla Public License Version
   * 1.1 (the "License"); you may not use this file except in compliance with
   * the License.  Alternatively, the contents of this file may be used under
   * the terms of the GNU Lesser General Public License Version 2.1 or later.
   *
   * Software distributed under the License is distributed on an "AS IS" basis,
   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   * for the specific language governing rights and limitations under the
   * License.
   */
  
  package javassist.util.proxy;
  
  import java.io.Serializable;
  import java.io.ObjectStreamException;
  
  /**
   * A proxy object is converted into an instance of this class
   * when it is written to an output stream.
   *
   * @see RuntimeSupport#makeSerializedProxy(Object)
   */
  class SerializedProxy implements Serializable {
      private String superClass;
      private String[] interfaces;
      private MethodFilter filter;
      private MethodHandler handler;
  
      SerializedProxy(Class proxy, MethodFilter f, MethodHandler h) {
          filter = f;
          handler = h;
          superClass = proxy.getSuperclass().getName();
          Class[] infs = proxy.getInterfaces();
          int n = infs.length;
          interfaces = new String[n - 1];
          String setterInf = ProxyObject.class.getName();
          for (int i = 0; i < n; i++) {
              String name = infs[i].getName();
              if (!name.equals(setterInf))
                  interfaces[i] = name;
          }
      }
  
      Object readResolve() throws ObjectStreamException {
          try {
              int n = interfaces.length;
              Class[] infs = new Class[n];
              for (int i = 0; i < n; i++)
                  infs[i] = Class.forName(interfaces[i]);
  
              ProxyFactory f = new ProxyFactory();
              f.setSuperclass(Class.forName(superClass));
              f.setInterfaces(infs);
              f.setFilter(filter);
              f.setHandler(handler);
              return f.createClass().newInstance();
          }
          catch (ClassNotFoundException e) {
              throw new java.io.InvalidClassException(e.getMessage());
          }
          catch (InstantiationException e2) {
              throw new java.io.InvalidObjectException(e2.getMessage());
          }
          catch (IllegalAccessException e3) {
              throw new java.io.InvalidClassException(e3.getMessage());
          }
      }
  }
  
  
  



More information about the jboss-cvs-commits mailing list