import java.lang.ref.WeakReference;
import javassist.CannotCompileException;
+import javassist.NotFoundException;
import javassist.bytecode.*;
/*
private static final String SERIAL_VERSION_UID_FIELD = "serialVersionUID";
private static final String SERIAL_VERSION_UID_TYPE = "J";
- private static final int SERIAL_VERSION_UID_VALUE = -1;
+ private static final long SERIAL_VERSION_UID_VALUE = -1L;
/**
* If true, a generated proxy class is cached and it will be reused
// HashMap allMethods = getMethods(superClass, interfaces);
// int size = allMethods.size();
makeConstructors(classname, cf, pool, classname);
- int s = overrideMethods(cf, pool, classname);
- addMethodsHolder(cf, pool, classname, s);
+
+ ArrayList forwarders = new ArrayList();
+ int s = overrideMethods(cf, pool, classname, forwarders);
+ addClassInitializer(cf, pool, classname, s, forwarders);
addSetter(classname, cf, pool);
if (!hasGetHandler)
addGetter(classname, cf, pool);
cf.setInterfaces(list);
}
- private static void addMethodsHolder(ClassFile cf, ConstPool cp,
- String classname, int size)
+ private static void addClassInitializer(ClassFile cf, ConstPool cp,
+ String classname, int size, ArrayList forwarders)
throws CannotCompileException
{
FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
cf.addField(finfo);
MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
minfo.setAccessFlags(AccessFlag.STATIC);
- Bytecode code = new Bytecode(cp, 0, 0);
+ setThrows(minfo, cp, new Class[] { ClassNotFoundException.class });
+
+ Bytecode code = new Bytecode(cp, 0, 2);
code.addIconst(size * 2);
code.addAnewarray("java.lang.reflect.Method");
+ final int varArray = 0;
+ code.addAstore(varArray);
+
+ // forName() must be called here. Otherwise, the class might be
+ // invisible.
+ code.addLdc(classname);
+ code.addInvokestatic("java.lang.Class",
+ "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
+ final int varClass = 1;
+ code.addAstore(varClass);
+
+ Iterator it = forwarders.iterator();
+ while (it.hasNext()) {
+ Find2MethodsArgs args = (Find2MethodsArgs)it.next();
+ callFind2Methods(code, args.methodName, args.delegatorName,
+ args.origIndex, args.descriptor, varClass, varArray);
+ }
+
+ code.addAload(varArray);
code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
- // also need to set serial version uid
- code.addLconst(-1L);
+
+ code.addLconst(SERIAL_VERSION_UID_VALUE);
code.addPutstatic(classname, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
code.addOpcode(Bytecode.RETURN);
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
}
+ /**
+ * @param thisMethod might be null.
+ */
+ private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
+ int index, String desc, int classVar, int arrayVar) {
+ String findClass = RuntimeSupport.class.getName();
+ String findDesc
+ = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
+
+ code.addAload(classVar);
+ code.addLdc(superMethod);
+ if (thisMethod == null)
+ code.addOpcode(Opcode.ACONST_NULL);
+ else
+ code.addLdc(thisMethod);
+
+ code.addIconst(index);
+ code.addLdc(desc);
+ code.addAload(arrayVar);
+ code.addInvokestatic(findClass, "find2Methods", findDesc);
+ }
+
private static void addSetter(String classname, ClassFile cf, ConstPool cp)
throws CannotCompileException
{
cf.addMethod(minfo);
}
- private int overrideMethods(ClassFile cf, ConstPool cp, String className)
+ private int overrideMethods(ClassFile cf, ConstPool cp, String className, ArrayList forwarders)
throws CannotCompileException
{
String prefix = makeUniqueName("_d", signatureMethods);
int mod = meth.getModifiers();
if (testBit(signature, index)) {
override(className, meth, prefix, index,
- keyToDesc(key, meth), cf, cp);
+ keyToDesc(key, meth), cf, cp, forwarders);
}
index++;
}
}
private void override(String thisClassname, Method meth, String prefix,
- int index, String desc, ClassFile cf, ConstPool cp)
+ int index, String desc, ClassFile cf, ConstPool cp, ArrayList forwarders)
throws CannotCompileException
{
Class declClass = meth.getDeclaringClass();
MethodInfo forwarder
= makeForwarder(thisClassname, meth, desc, cp, declClass,
- delegatorName, index);
+ delegatorName, index, forwarders);
cf.addMethod(forwarder);
}
*/
private static MethodInfo makeForwarder(String thisClassName,
Method meth, String desc, ConstPool cp,
- Class declClass, String delegatorName, int index) {
+ Class declClass, String delegatorName, int index,
+ ArrayList forwarders) {
MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
forwarder.setAccessFlags(Modifier.FINAL
| (meth.getModifiers() & ~(Modifier.ABSTRACT
int args = Descriptor.paramSize(desc);
Bytecode code = new Bytecode(cp, 0, args + 2);
/*
- * if (methods[index * 2] == null) {
+ * static {
* methods[index * 2]
* = RuntimeSupport.findSuperMethod(this, <overridden name>, <desc>);
* methods[index * 2 + 1]
* = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
* or = null // the original method is abstract.
* }
+ * :
* return ($r)handler.invoke(this, methods[index * 2],
* methods[index * 2 + 1], $args);
*/
code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
code.addAstore(arrayVar);
- callFind2Methods(code, meth.getName(), delegatorName, origIndex, desc, arrayVar);
+ forwarders.add(new Find2MethodsArgs(meth.getName(), delegatorName, desc, origIndex));
code.addAload(0);
code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
return forwarder;
}
+ static class Find2MethodsArgs {
+ String methodName, delegatorName, descriptor;
+ int origIndex;
+
+ Find2MethodsArgs(String mname, String dname, String desc, int index) {
+ methodName = mname;
+ delegatorName = dname;
+ descriptor = desc;
+ origIndex = index;
+ }
+ }
+
private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
Class[] exceptions = orig.getExceptionTypes();
setThrows(minfo, cp, exceptions);
return regno + FactoryHelper.dataSize[index];
}
- /**
- * @param thisMethod might be null.
- */
- private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
- int index, String desc, int arrayVar) {
- String findClass = RuntimeSupport.class.getName();
- String findDesc
- = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
-
- code.addAload(0);
- code.addLdc(superMethod);
- if (thisMethod == null)
- code.addOpcode(Opcode.ACONST_NULL);
- else
- code.addLdc(thisMethod);
-
- code.addIconst(index);
- code.addLdc(desc);
- code.addAload(arrayVar);
- code.addInvokestatic(findClass, "find2Methods", findDesc);
- }
-
private static void addUnwrapper(Bytecode code, Class type) {
if (type.isPrimitive()) {
if (type == Void.TYPE)
* @throws RuntimeException if the methods are not found.
* @see javassist.util.proxy.ProxyFactory
*/
- public static void find2Methods(Object self, String superMethod,
+ public static void find2Methods(Class clazz, String superMethod,
String thisMethod, int index,
String desc, java.lang.reflect.Method[] methods)
{
- /* Once methods[index] and methods[index + 1] are set to non-null,
- * then their values never change.
- */
- if (methods[index] == null || methods[index + 1] == null) {
- Method m1 = thisMethod == null ? null
- : findMethod(self, thisMethod, desc);
- Method m0 = findSuperMethod(self, superMethod, desc);
- synchronized (methods) {
- if (methods[index] == null) {
- methods[index + 1] = m1;
- methods[index] = m0;
- }
- }
- }
+ methods[index + 1] = thisMethod == null ? null
+ : findMethod(clazz, thisMethod, desc);
+ methods[index] = findSuperMethod(clazz, superMethod, desc);
}
/**
*
* @throws RuntimeException if the method is not found.
*/
- public static Method findMethod(Object self, String name, String desc) {
- Method m = findMethod2(self.getClass(), name, desc);
+ public static Method findMethod(Class clazz, String name, String desc) {
+ Method m = findMethod2(clazz, name, desc);
if (m == null)
- error(self, name, desc);
+ error(clazz, name, desc);
return m;
}
*
* @throws RuntimeException if the method is not found.
*/
- public static Method findSuperMethod(Object self, String name, String desc) {
- Class clazz = self.getClass();
+ public static Method findSuperMethod(Class clazz, String name, String desc) {
Method m = findSuperMethod2(clazz.getSuperclass(), name, desc);
if (m == null)
m = searchInterfaces(clazz, name, desc);
if (m == null)
- error(self, name, desc);
+ error(clazz, name, desc);
return m;
}
- private static void error(Object self, String name, String desc) {
+ private static void error(Class clazz, String name, String desc) {
throw new RuntimeException("not found " + name + ":" + desc
- + " in " + self.getClass().getName());
+ + " in " + clazz.getName());
}
private static Method findSuperMethod2(Class clazz, String name, String desc) {