Browse Source

fixed JASSIST-144

git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@591 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 12 years ago
parent
commit
3ad4da6d8c

+ 1
- 1
Readme.html View 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

+ 33
- 0
src/main/javassist/util/proxy/Proxy.java View File

@@ -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);
}

+ 39
- 11
src/main/javassist/util/proxy/ProxyFactory.java View 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());

+ 10
- 3
src/main/javassist/util/proxy/ProxyObject.java View 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();
}

+ 1
- 1
src/main/javassist/util/proxy/ProxyObjectOutputStream.java View 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);
}

+ 2
- 0
src/main/javassist/util/proxy/RuntimeSupport.java View 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);
}

+ 3
- 2
src/main/javassist/util/proxy/SerializedProxy.java View 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;
}

+ 8
- 0
src/test/javassist/JvstTest.java View 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;
}
}

+ 52
- 0
src/test/javassist/proxyfactory/Tester.java View File

@@ -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());
}
}

Loading…
Cancel
Save