git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@591 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -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 |
@@ -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); | |||
} |
@@ -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()); |
@@ -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(); | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |