From 3ad4da6d8cd5f11a8009c70f59d613b52cf4b50d Mon Sep 17 00:00:00 2001 From: chiba Date: Thu, 1 Sep 2011 10:11:05 +0000 Subject: [PATCH] fixed JASSIST-144 git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@591 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- Readme.html | 2 +- src/main/javassist/util/proxy/Proxy.java | 33 ++++++++++++ .../javassist/util/proxy/ProxyFactory.java | 50 ++++++++++++++---- .../javassist/util/proxy/ProxyObject.java | 13 +++-- .../util/proxy/ProxyObjectOutputStream.java | 2 +- .../javassist/util/proxy/RuntimeSupport.java | 2 + .../javassist/util/proxy/SerializedProxy.java | 5 +- src/test/javassist/JvstTest.java | 8 +++ src/test/javassist/proxyfactory/Tester.java | 52 +++++++++++++++++++ 9 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 src/main/javassist/util/proxy/Proxy.java create mode 100644 src/test/javassist/proxyfactory/Tester.java diff --git a/Readme.html b/Readme.html index 07908f5b..f53e4680 100644 --- a/Readme.html +++ b/Readme.html @@ -283,7 +283,7 @@ see javassist.Dump.

-version 3.16

-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 index 00000000..c446523f --- /dev/null +++ b/src/main/javassist/util/proxy/Proxy.java @@ -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); +} diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index 721f58c8..9bce51fa 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -63,9 +63,11 @@ import javassist.bytecode.*; * } * }; * Foo foo = (Foo)c.newInstance(); - * ((ProxyObject)foo).setHandler(mi); + * ((Proxy)foo).setHandler(mi); * * + *

Here, Method is java.lang.reflect.Method.

+ * *

Then, the following method call will be forwarded to MethodHandler * mi and prints a message before executing the originally called method * bar() in Foo. @@ -88,7 +90,7 @@ import javassist.bytecode.*; * *

* *

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()); diff --git a/src/main/javassist/util/proxy/ProxyObject.java b/src/main/javassist/util/proxy/ProxyObject.java index 46a0fbee..f04ae9a4 100644 --- a/src/main/javassist/util/proxy/ProxyObject.java +++ b/src/main/javassist/util/proxy/ProxyObject.java @@ -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 getHandler() method. If the super class + * has getHandler, then Proxy 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(); } diff --git a/src/main/javassist/util/proxy/ProxyObjectOutputStream.java b/src/main/javassist/util/proxy/ProxyObjectOutputStream.java index 85a9adf7..31c3861b 100644 --- a/src/main/javassist/util/proxy/ProxyObjectOutputStream.java +++ b/src/main/javassist/util/proxy/ProxyObjectOutputStream.java @@ -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); } diff --git a/src/main/javassist/util/proxy/RuntimeSupport.java b/src/main/javassist/util/proxy/RuntimeSupport.java index c11c72d8..687fc8dc 100644 --- a/src/main/javassist/util/proxy/RuntimeSupport.java +++ b/src/main/javassist/util/proxy/RuntimeSupport.java @@ -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); } diff --git a/src/main/javassist/util/proxy/SerializedProxy.java b/src/main/javassist/util/proxy/SerializedProxy.java index 3bb13856..36425a88 100644 --- a/src/main/javassist/util/proxy/SerializedProxy.java +++ b/src/main/javassist/util/proxy/SerializedProxy.java @@ -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; } diff --git a/src/test/javassist/JvstTest.java b/src/test/javassist/JvstTest.java index 92154b38..f4ccaf6c 100644 --- a/src/test/javassist/JvstTest.java +++ b/src/test/javassist/JvstTest.java @@ -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 index 00000000..39033885 --- /dev/null +++ b/src/test/javassist/proxyfactory/Tester.java @@ -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()); + } +} -- 2.39.5