<p>-version 3.16
<ul>
- <li>JIRA JASSIST-127
+ <li>JIRA JASSIST-127, 144
</ul>
<p>-version 3.15 on July 8, 2011
--- /dev/null
+/*
+ * 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);
+}
* }
* };
* 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>.
*
* <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
* 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)}.
*
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;
*/
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));
}
/**
handler = null;
signature = null;
signatureMethods = null;
+ hasGetHandler = false;
thisClass = null;
writeDirectory = null;
factoryUseCache = useCache;
}
}
+ /**
+ * 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.
*
InstantiationException, IllegalAccessException, InvocationTargetException
{
Object obj = create(paramTypes, args);
- ((ProxyObject)obj).setHandler(mh);
+ ((Proxy)obj).setHandler(mh);
return obj;
}
* 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.
*/
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
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 {
HashMap allMethods = getMethods(superClass, interfaces);
signatureMethods = new ArrayList(allMethods.entrySet());
+ hasGetHandler = allMethods.get(HANDLER_GETTER_KEY) != null;
Collections.sort(signatureMethods, sorter);
}
}
}
- 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 };
}
}
+ 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());
/**
* 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.
/**
* 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();
}
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);
}
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);
}
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;
}
}
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;
}
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;
}
}
--- /dev/null
+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());
+ }
+}