Преглед изворни кода

made a proxy class serializable (JASSIST-20).


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@329 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba пре 17 година
родитељ
комит
56af2ace49

+ 2
- 1
src/main/javassist/bytecode/ClassFile.java Прегледај датотеку

@@ -545,7 +545,8 @@ public final class ClassFile {
&& notBridgeMethod(minfo) && notBridgeMethod(newMinfo)
&& Descriptor.eqParamTypes(minfo.getDescriptor(),
descriptor))
throw new CannotCompileException("duplicate method: " + name);
throw new CannotCompileException("duplicate method: " + name
+ " in " + this.getName());
}
}


+ 89
- 38
src/main/javassist/util/proxy/ProxyFactory.java Прегледај датотеку

@@ -32,6 +32,11 @@ import java.lang.ref.WeakReference;
import javassist.CannotCompileException;
import javassist.bytecode.*;

/*
* This class is implemented only with the lower-level API of Javassist.
* This design decision is for maximizing performance.
*/

/**
* Factory of dynamic proxy classes.
*
@@ -92,6 +97,11 @@ import javassist.bytecode.*;
* }
* </pre></ul>
*
* <p>A proxy object generated by <code>ProxyFactory</code> is serializable
* if its super class or interfaces implement a <code>java.io.Serializable</code>.
* However, a serialized proxy object will not be compatible with future releases.
* The serialization support should be used for short-term storage or RMI.
*
* @see MethodHandler
* @since 3.1
*/
@@ -117,6 +127,7 @@ public class ProxyFactory {

private static final String HOLDER = "_methods_";
private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
private static final String METHOD_FILTER_FIELD = "_method_filter";
private static final String HANDLER = "handler";
private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
@@ -137,8 +148,8 @@ public class ProxyFactory {
private static WeakHashMap proxyCache = new WeakHashMap();

static class CacheKey {
private String classes;
private MethodFilter filter;
String classes;
MethodFilter filter;
private int hash;
WeakReference proxyClass;
MethodHandler handler;
@@ -233,10 +244,12 @@ public class ProxyFactory {
public Class createClass() {
if (thisClass == null) {
ClassLoader cl = getClassLoader();
if (useCache)
createClass2(cl);
else
createClass3(cl);
synchronized (proxyCache) {
if (useCache)
createClass2(cl);
else
createClass3(cl);
}
}

return thisClass;
@@ -244,7 +257,12 @@ public class ProxyFactory {

private void createClass2(ClassLoader cl) {
CacheKey key = new CacheKey(superClass, interfaces, methodFilter, handler);
synchronized (proxyCache) {
/*
* Excessive concurrency causes a large memory footprint and slows the
* execution speed down (with JDK 1.5). Thus, we use a jumbo lock for
* reducing concrrency.
*/
// synchronized (proxyCache) {
HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
if (cacheForTheLoader == null) {
cacheForTheLoader = new HashMap();
@@ -264,9 +282,9 @@ public class ProxyFactory {
}
}
}
}
// }

synchronized (key) {
// synchronized (key) {
Class c = isValidEntry(key);
if (c == null) {
createClass3(cl);
@@ -274,7 +292,7 @@ public class ProxyFactory {
}
else
thisClass = c;
}
// }
}

private Class isValidEntry(CacheKey key) {
@@ -295,7 +313,8 @@ public class ProxyFactory {
FactoryHelper.writeFile(cf, writeDirectory);

thisClass = FactoryHelper.toClass(cf, cl, getDomain());
setHandler();
setField(DEFAULT_INTERCEPTOR, handler);
setField(METHOD_FILTER_FIELD, methodFilter);
}
catch (CannotCompileException e) {
throw new RuntimeException(e.getMessage(), e);
@@ -303,6 +322,40 @@ public class ProxyFactory {

}

private void setField(String fieldName, Object value) {
if (thisClass != null && value != null)
try {
Field f = thisClass.getField(fieldName);
f.setAccessible(true);
f.set(null, value);
f.setAccessible(false);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}

static MethodFilter getFilter(Class clazz) {
return (MethodFilter)getField(clazz, METHOD_FILTER_FIELD);
}

static MethodHandler getHandler(Class clazz) {
return (MethodHandler)getField(clazz, DEFAULT_INTERCEPTOR);
}

private static Object getField(Class clazz, String fieldName) {
try {
Field f = clazz.getField(fieldName);
f.setAccessible(true);
Object value = f.get(null);
f.setAccessible(false);
return value;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* A provider of class loaders.
*
@@ -403,33 +456,7 @@ public class ProxyFactory {
*/
public void setHandler(MethodHandler mi) {
handler = mi;
setHandler();
}

private void setHandler() {
if (thisClass != null && handler != null)
try {
Field f = thisClass.getField(DEFAULT_INTERCEPTOR);
f.setAccessible(true);
f.set(null, handler);
f.setAccessible(false);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}

static MethodHandler getHandler(Class clazz) {
try {
Field f = clazz.getField(DEFAULT_INTERCEPTOR);
f.setAccessible(true);
MethodHandler h = (MethodHandler)f.get(null);
f.setAccessible(false);
return h;
}
catch (Exception e) {
throw new RuntimeException(e);
}
setField(DEFAULT_INTERCEPTOR, handler);
}

private static int counter = 0;
@@ -473,6 +500,11 @@ public class ProxyFactory {
finfo2.setAccessFlags(AccessFlag.PRIVATE);
cf.addField(finfo2);

FieldInfo finfo3 = new FieldInfo(pool, METHOD_FILTER_FIELD,
"Ljavassist/util/proxy/MethodFilter;");
finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
cf.addField(finfo3);

HashMap allMethods = getMethods(superClass, interfaces);
int size = allMethods.size();
makeConstructors(classname, cf, pool, classname);
@@ -480,6 +512,8 @@ public class ProxyFactory {
addMethodsHolder(cf, pool, classname, s);
addSetter(classname, cf, pool);

cf.addMethod(makeWriteReplace(pool));

thisClass = null;
return cf;
}
@@ -932,4 +966,21 @@ public class ProxyFactory {
else
code.addCheckcast(type.getName());
}

private static MethodInfo makeWriteReplace(ConstPool cp) {
MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
String[] list = new String[1];
list[0] = "java.io.ObjectStreamException";
ExceptionsAttribute ea = new ExceptionsAttribute(cp);
ea.setExceptions(list);
minfo.setExceptionsAttribute(ea);
Bytecode code = new Bytecode(cp, 0, 1);
code.addAload(0);
code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
"makeSerializedProxy",
"(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
code.addOpcode(Opcode.ARETURN);
minfo.setCodeAttribute(code.toCodeAttribute());
return minfo;
}
}

+ 19
- 1
src/main/javassist/util/proxy/RuntimeSupport.java Прегледај датотеку

@@ -16,6 +16,7 @@
package javassist.util.proxy;

import java.lang.reflect.Method;
import java.io.Serializable;

/**
* Runtime support routines that the classes generated by ProxyFactory use.
@@ -26,7 +27,9 @@ public class RuntimeSupport {
/**
* A method handler that only executes a method.
*/
public static MethodHandler default_interceptor = new MethodHandler() {
public static MethodHandler default_interceptor = new DefaultMethodHandler();

static class DefaultMethodHandler implements MethodHandler, Serializable {
public Object invoke(Object self, Method m,
Method proceed, Object[] args)
throws Exception
@@ -166,4 +169,19 @@ public class RuntimeSupport {
sbuf.append('L').append(type.getName().replace('.', '/'))
.append(';');
}

/**
* Converts a proxy object to an object that is writable to an
* object stream. This method is called by <code>writeReplace()</code>
* in a proxy class.
*
* @since 3.4
*/
public static SerializedProxy makeSerializedProxy(Object proxy)
throws java.io.InvalidClassException
{
Class clazz = proxy.getClass();
return new SerializedProxy(clazz, ProxyFactory.getFilter(clazz),
ProxyFactory.getHandler(clazz));
}
}

+ 72
- 0
src/main/javassist/util/proxy/SerializedProxy.java Прегледај датотеку

@@ -0,0 +1,72 @@
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999-2006 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.
*
* 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;

import java.io.Serializable;
import java.io.ObjectStreamException;

/**
* A proxy object is converted into an instance of this class
* when it is written to an output stream.
*
* @see RuntimeSupport#makeSerializedProxy(Object)
*/
class SerializedProxy implements Serializable {
private String superClass;
private String[] interfaces;
private MethodFilter filter;
private MethodHandler handler;

SerializedProxy(Class proxy, MethodFilter f, MethodHandler h) {
filter = f;
handler = h;
superClass = proxy.getSuperclass().getName();
Class[] infs = proxy.getInterfaces();
int n = infs.length;
interfaces = new String[n - 1];
String setterInf = ProxyObject.class.getName();
for (int i = 0; i < n; i++) {
String name = infs[i].getName();
if (!name.equals(setterInf))
interfaces[i] = name;
}
}

Object readResolve() throws ObjectStreamException {
try {
int n = interfaces.length;
Class[] infs = new Class[n];
for (int i = 0; i < n; i++)
infs[i] = Class.forName(interfaces[i]);

ProxyFactory f = new ProxyFactory();
f.setSuperclass(Class.forName(superClass));
f.setInterfaces(infs);
f.setFilter(filter);
f.setHandler(handler);
return f.createClass().newInstance();
}
catch (ClassNotFoundException e) {
throw new java.io.InvalidClassException(e.getMessage());
}
catch (InstantiationException e2) {
throw new java.io.InvalidObjectException(e2.getMessage());
}
catch (IllegalAccessException e3) {
throw new java.io.InvalidClassException(e3.getMessage());
}
}
}

Loading…
Откажи
Сачувај