]> source.dussan.org Git - javassist.git/commitdiff
fixed JASSIST-144
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 1 Sep 2011 10:11:05 +0000 (10:11 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 1 Sep 2011 10:11:05 +0000 (10:11 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@591 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

Readme.html
src/main/javassist/util/proxy/Proxy.java [new file with mode: 0644]
src/main/javassist/util/proxy/ProxyFactory.java
src/main/javassist/util/proxy/ProxyObject.java
src/main/javassist/util/proxy/ProxyObjectOutputStream.java
src/main/javassist/util/proxy/RuntimeSupport.java
src/main/javassist/util/proxy/SerializedProxy.java
src/test/javassist/JvstTest.java
src/test/javassist/proxyfactory/Tester.java [new file with mode: 0644]

index 07908f5b197ecda43a490eae98de37dc4145b8bd..f53e46807fcd76b82fcff899ed02db3d9b5d1152 100644 (file)
@@ -283,7 +283,7 @@ see javassist.Dump.
 
 <p>-version 3.16
 <ul>
-       <li>JIRA JASSIST-127
+       <li>JIRA JASSIST-127, 144
 </ul>
 
 <p>-version 3.15 on July 8, 2011
diff --git a/src/main/javassist/util/proxy/Proxy.java b/src/main/javassist/util/proxy/Proxy.java
new file mode 100644 (file)
index 0000000..c446523
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999- 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,
+ * or the Apache License Version 2.0.
+ *
+ * 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;
+
+/**
+ * The interface implemented by proxy classes.
+ * This interface only provides a setter method.
+ * To obtain a handler, call {@link ProxyFactory#getHandler(Proxy)}.
+ *
+ * @see ProxyFactory
+ * @see 3.16
+ */
+public interface Proxy {
+    /**
+     * Sets a handler.  It can be used for changing handlers
+     * during runtime.
+     */
+    void setHandler(MethodHandler mi);
+}
index 721f58c83fdd27426f5e97ff88783f248f1623da..9bce51fafca7ab6cb9eb8b07f2960456ee4a5994 100644 (file)
@@ -63,9 +63,11 @@ import javassist.bytecode.*;
  *     }
  * };
  * Foo foo = (Foo)c.newInstance();
- * ((ProxyObject)foo).setHandler(mi);
+ * ((Proxy)foo).setHandler(mi);
  * </pre></ul>
  *
+ * <p>Here, <code>Method</code> is <code>java.lang.reflect.Method</code>.</p>
+ *
  * <p>Then, the following method call will be forwarded to MethodHandler
  * <code>mi</code> and prints a message before executing the originally called method
  * <code>bar()</code> in <code>Foo</code>.
@@ -88,7 +90,7 @@ import javassist.bytecode.*;
  *
  * <ul><pre>
  * MethodHandler mi = ... ;    // alternative handler
- * ((ProxyObject)foo).setHandler(mi);
+ * ((Proxy)foo).setHandler(mi);
  * </pre></ul>
  *
  * <p> If setHandler is never called for a proxy instance then it will
@@ -119,7 +121,7 @@ import javassist.bytecode.*;
  * with previous releases of javassist. Unfortunately,this legacy behaviour makes caching
  * and reuse of proxy classes impossible. The current programming model expects javassist
  * clients to set the handler of a proxy instance explicitly by calling method
- * {@link ProxyObject#setHandler(MethodHandler)} as shown in the sample code above. New
+ * {@link Proxy#setHandler(MethodHandler)} as shown in the sample code above. New
  * clients are strongly recommended to use this model rather than calling
  * {@link ProxyFactory#setHandler(MethodHandler)}.
  *
@@ -156,6 +158,7 @@ public class ProxyFactory {
     private MethodFilter methodFilter;
     private MethodHandler handler;  // retained for legacy usage
     private List signatureMethods;
+    private boolean hasGetHandler;
     private byte[] signature;
     private String classname;
     private String basename;
@@ -293,8 +296,8 @@ public class ProxyFactory {
      */
     public static boolean isProxyClass(Class cl)
     {
-        // all proxies implement ProxyObject. nothing else should. 
-        return (ProxyObject.class.isAssignableFrom(cl));
+        // all proxies implement Proxy or ProxyObject. nothing else should. 
+        return (Proxy.class.isAssignableFrom(cl));
     }
 
     /**
@@ -338,6 +341,7 @@ public class ProxyFactory {
         handler = null;
         signature = null;
         signatureMethods = null;
+        hasGetHandler = false;
         thisClass = null;
         writeDirectory = null;
         factoryUseCache = useCache;
@@ -542,6 +546,26 @@ public class ProxyFactory {
         }
     }
 
+    /**
+     * Obtains the method handler of the given proxy object.
+     * 
+     * @param p     a proxy object.
+     * @return the method handler.
+     * @since 3.16
+     */
+    public static MethodHandler getHandler(Proxy p) {
+        try {
+            Field f = p.getClass().getDeclaredField(HANDLER);
+            f.setAccessible(true);
+            Object value = f.get(p);
+            f.setAccessible(false);
+            return (MethodHandler)value;
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     /**
      * A provider of class loaders.
      *
@@ -633,7 +657,7 @@ public class ProxyFactory {
                InstantiationException, IllegalAccessException, InvocationTargetException
     {
         Object obj = create(paramTypes, args);
-        ((ProxyObject)obj).setHandler(mh);
+        ((Proxy)obj).setHandler(mh);
         return obj;
     }
 
@@ -658,7 +682,7 @@ public class ProxyFactory {
      * specified.
      * @deprecated since 3.12
      * use of this method is incompatible  with proxy class caching.
-     * instead clients should call method {@link ProxyObject#setHandler(MethodHandler)} to set the handler
+     * instead clients should call method {@link Proxy#setHandler(MethodHandler)} to set the handler
      * for each newly created  proxy instance.
      * calling this method will automatically disable caching of classes created by the proxy factory.
      */
@@ -684,7 +708,7 @@ public class ProxyFactory {
     private ClassFile make() throws CannotCompileException {
         ClassFile cf = new ClassFile(false, classname, superName);
         cf.setAccessFlags(AccessFlag.PUBLIC);
-        setInterfaces(cf, interfaces);
+        setInterfaces(cf, interfaces, hasGetHandler ? Proxy.class : ProxyObject.class);
         ConstPool pool = cf.getConstPool();
 
         // legacy: we only add the static field for the default interceptor if caching is disabled
@@ -715,7 +739,8 @@ public class ProxyFactory {
         int s = overrideMethods(cf, pool, classname);
         addMethodsHolder(cf, pool, classname, s);
         addSetter(classname, cf, pool);
-        addGetter(classname, cf, pool);
+        if (!hasGetHandler)
+            addGetter(classname, cf, pool);
 
         if (factoryWriteReplace) {
             try {
@@ -774,6 +799,7 @@ public class ProxyFactory {
 
         HashMap allMethods = getMethods(superClass, interfaces);
         signatureMethods = new ArrayList(allMethods.entrySet());
+        hasGetHandler = allMethods.get(HANDLER_GETTER_KEY) != null;
         Collections.sort(signatureMethods, sorter);
     }
 
@@ -833,8 +859,8 @@ public class ProxyFactory {
         }
     }
 
-    private static void setInterfaces(ClassFile cf, Class[] interfaces) {
-        String setterIntf = ProxyObject.class.getName();
+    private static void setInterfaces(ClassFile cf, Class[] interfaces, Class proxyClass) {
+        String setterIntf = proxyClass.getName();
         String[] list;
         if (interfaces == null || interfaces.length == 0)
             list = new String[] { setterIntf };
@@ -1055,6 +1081,8 @@ public class ProxyFactory {
             }
     }
 
+    private static final String HANDLER_GETTER_KEY = HANDLER_GETTER + ":()";
+
     private static String keyToDesc(String key, Method m) {
         String params = key.substring(key.indexOf(':') + 1);
         return RuntimeSupport.makeDescriptor(params, m.getReturnType());
index 46a0fbeeea6ce727d0b2f96d77a76606a043b85e..f04ae9a49e8916435bd76e630738f9cb57c374ea 100644 (file)
@@ -18,10 +18,15 @@ package javassist.util.proxy;
 
 /**
  * The interface implemented by proxy classes.
+ * This interface is available only if the super class of the proxy object
+ * does not have a <code>getHandler()</code> method.  If the super class
+ * has <code>getHandler</code>, then <code>Proxy</code> interface is
+ * available.  
  *
  * @see ProxyFactory
+ * @see Proxy
  */
-public interface ProxyObject {
+public interface ProxyObject extends Proxy {
     /**
      * Sets a handler.  It can be used for changing handlers
      * during runtime.
@@ -30,8 +35,10 @@ public interface ProxyObject {
 
     /**
      * Get the handler.
-     * This can be used to access values of the underlying MethodHandler
-     * or to serialize it properly. 
+     * This can be used to access the underlying MethodHandler
+     * or to serialize it properly.
+     *
+     * @see ProxyFactory#getHandler(Proxy)
      */
     MethodHandler getHandler();
 }
index 85a9adf7b82ca903c47d6c9d35ee9d22260c70d5..31c3861beaca55f8d7e414df7182b8ac1abef1d0 100644 (file)
@@ -57,7 +57,7 @@ public class ProxyObjectOutputStream extends ObjectOutputStream
             writeInt(interfaces.length - 1);
             for (int i = 0; i < interfaces.length; i++) {
                 Class interfaze = interfaces[i];
-                if (interfaze != ProxyObject.class) {
+                if (interfaze != ProxyObject.class && interfaze != Proxy.class) {
                     name = interfaces[i].getName();
                     writeObject(name);
                 }
index c11c72d89071f060521200e4c701b41a3a9d4adf..687fc8dc204524810fe2ffab6929676133f87091 100644 (file)
@@ -220,6 +220,8 @@ public class RuntimeSupport {
         MethodHandler methodHandler = null;
         if (proxy instanceof ProxyObject)
             methodHandler = ((ProxyObject)proxy).getHandler();
+        else if (proxy instanceof Proxy)
+            methodHandler = ProxyFactory.getHandler((Proxy)proxy);
 
         return new SerializedProxy(clazz, ProxyFactory.getFilterSignature(clazz), methodHandler);
     }
index 3bb13856dadec7756bf67e2df7599db80d398fd2..36425a88f3d12f416f2125d71ac63233aecaccfc 100644 (file)
@@ -43,9 +43,10 @@ class SerializedProxy implements Serializable {
         int n = infs.length;
         interfaces = new String[n - 1];
         String setterInf = ProxyObject.class.getName();
+        String setterInf2 = Proxy.class.getName();
         for (int i = 0; i < n; i++) {
             String name = infs[i].getName();
-            if (!name.equals(setterInf))
+            if (!name.equals(setterInf) && !name.equals(setterInf2))
                 interfaces[i] = name;
         }
     }
@@ -81,7 +82,7 @@ class SerializedProxy implements Serializable {
             ProxyFactory f = new ProxyFactory();
             f.setSuperclass(loadClass(superClass));
             f.setInterfaces(infs);
-            ProxyObject proxy = (ProxyObject)f.createClass(filterSignature).newInstance();
+            Proxy proxy = (Proxy)f.createClass(filterSignature).newInstance();
             proxy.setHandler(handler);
             return proxy;
         }
index 92154b38fbae6dfd3dd441b642905ecdb74381d9..f4ccaf6c16aca7605e3a2404809ca3e85d4c6f68 100644 (file)
@@ -1118,6 +1118,14 @@ public class JvstTest extends JvstTestRoot {
         suite.addTestSuite(testproxy.ProxyTester.class);
         // suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class);
         suite.addTestSuite(javassist.proxyfactory.ProxyFactoryTest.class);
+        suite.addTestSuite(javassist.proxyfactory.Tester.class);
+        suite.addTestSuite(test.javassist.proxy.ProxySerializationTest.class);
+        suite.addTestSuite(test.javassist.convert.ArrayAccessReplaceTest.class);
+        suite.addTestSuite(test.javassist.proxy.JASSIST113RegressionTest.class);
+        //suite.addTestSuite(test.javassist.proxy.ProxyCacheGCTest.class);
+        suite.addTestSuite(test.javassist.proxy.ProxyFactoryCompatibilityTest.class);
+        suite.addTestSuite(test.javassist.proxy.ProxySerializationTest.class);
+        suite.addTestSuite(test.javassist.proxy.ProxySimpleTest.class);
         return suite;
     }
 }
diff --git a/src/test/javassist/proxyfactory/Tester.java b/src/test/javassist/proxyfactory/Tester.java
new file mode 100644 (file)
index 0000000..3903388
--- /dev/null
@@ -0,0 +1,52 @@
+package javassist.proxyfactory;
+
+import junit.framework.*;
+import javassist.util.proxy.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+
+class Hand implements java.io.Serializable {
+    public int setHandler(int i) { return i; }
+    int getHandler() { return 3; }
+}
+
+public class Tester extends TestCase {
+    static class MHandler implements MethodHandler, java.io.Serializable {
+        public Object invoke(Object self, Method m, Method proceed,
+                             Object[] args) throws Throwable {
+            System.out.println("Name: " + m.getName());
+            return proceed.invoke(self, args);
+        }
+    }
+
+    static MethodHandler mi = new MHandler();
+
+    public void test() throws Exception {
+        ProxyFactory f = new ProxyFactory();
+        f.setSuperclass(Hand.class);
+        Class c = f.createClass();
+        Hand foo = (Hand)c.newInstance();
+        ((Proxy)foo).setHandler(mi);
+        assertTrue(ProxyFactory.isProxyClass(c));
+        assertEquals(3, foo.getHandler());
+    }
+
+    public void test2() throws Exception {
+        ProxyFactory f = new ProxyFactory();
+        f.setSuperclass(Hand.class);
+        Hand h = (Hand)f.create(new Class[0], new Object[0], mi);
+        assertEquals(3, h.getHandler());
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ProxyObjectOutputStream out = new ProxyObjectOutputStream(bos);
+        out.writeObject(h);
+        out.close();
+        byte[] bytes = bos.toByteArray();
+        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+        ProxyObjectInputStream in = new ProxyObjectInputStream(bis);
+        Hand h2 = (Hand)in.readObject();
+        assertEquals(3, h2.getHandler());
+    }
+}