com.firefly.utils.classproxy.JavassistClassProxyFactory Maven / Gradle / Ivy
package com.firefly.utils.classproxy;
import com.firefly.utils.ReflectUtils.MethodProxy;
import com.firefly.utils.StringUtils;
import javassist.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class JavassistClassProxyFactory implements ClassProxyFactory {
public static final JavassistClassProxyFactory INSTANCE = new JavassistClassProxyFactory();
public static ClassLoader classLoader;
static {
classLoader = Thread.currentThread().getContextClassLoader();
}
private JavassistClassProxyFactory() {
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public T createProxy(T instance, ClassProxy proxy, MethodFilter filter) throws Throwable {
ClassPool classPool = ClassPool.getDefault();
classPool.insertClassPath(new ClassClassPath(ClassProxyFactory.class));
Class clazz = instance.getClass();
// make class
CtClass cc = classPool.makeClass("com.firefly.utils.ClassProxy" + UUID.randomUUID().toString().replace("-", ""));
cc.setSuperclass(classPool.get(clazz.getName()));
// make fields
cc.addField(CtField.make("private " + ClassProxy.class.getCanonicalName() + " classProxy;", cc));
cc.addField(CtField.make("private " + clazz.getCanonicalName() + " originalInstance;", cc));
cc.addField(CtField.make("private " + MethodProxy[].class.getCanonicalName() + " methodProxies;", cc));
// make constructor
CtConstructor empty = new CtConstructor(null, cc);
empty.setBody("{}");
CtConstructor constructor = new CtConstructor(new CtClass[]{
classPool.get(ClassProxy.class.getName()),
classPool.get(clazz.getName()),
classPool.get(MethodProxy[].class.getName())
}, cc);
constructor.setBody("{"
+ "this.classProxy = (" + ClassProxy.class.getCanonicalName() + ")$1;"
+ "this.originalInstance = (" + clazz.getCanonicalName() + ")$2;"
+ "this.methodProxies = (" + MethodProxy[].class.getCanonicalName() + ")$3;"
+ "}");
cc.addConstructor(empty);
cc.addConstructor(constructor);
// make methods
List list = new ArrayList<>();
for (Method m : clazz.getMethods()) {
if (m.getDeclaringClass().equals(Object.class)
|| Modifier.isFinal(m.getModifiers())
|| Modifier.isStatic(m.getModifiers())
|| Modifier.isNative(m.getModifiers())) {
continue;
}
if (filter != null && !filter.accept(m)) {
continue;
}
list.add(m);
}
Method[] methods = list.toArray(new Method[0]);
MethodProxy[] methodProxies = new MethodProxy[methods.length];
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
methodProxies[i] = JavassistReflectionProxyFactory.INSTANCE.getMethodProxy(m);
String parameterArray = "Object[] args = new Object[]{";
String str = "public " + m.getReturnType().getCanonicalName() + " " + m.getName() + "(";
Class[] parameters = m.getParameterTypes();
for (int j = 0; j < parameters.length; j++) {
if (j != 0) {
str += ", ";
parameterArray += ", ";
}
str += parameters[j].getCanonicalName() + " arg" + j;
if (parameters[j].isPrimitive()) {
parameterArray += StringUtils.replace("(Object){}.valueOf(", AbstractProxyFactory.primitiveWrapMap.get(parameters[j]))
+ "arg" + j + ")";
} else {
parameterArray += "(Object)arg" + j;
}
}
str += "){\n";
parameterArray += "};\n";
if (parameters.length == 0) {
parameterArray = Object[].class.getCanonicalName() + " args = new Object[0];\n";
}
str += "\t" + parameterArray;
if (!m.getReturnType().equals(void.class)) {
if (m.getReturnType().isPrimitive()) {
str += "\t" + m.getReturnType().getCanonicalName() + " ret = (("
+ AbstractProxyFactory.primitiveWrapMap.get(m.getReturnType()) + ")"
+ "classProxy.intercept(methodProxies[" + i + "], "
+ "originalInstance, "
+ "args"
+ "))." + m.getReturnType().getCanonicalName() + "Value()"
+ ";\n";
} else {
str += "\t" + m.getReturnType().getCanonicalName() + " ret = ("
+ m.getReturnType().getCanonicalName() + ")"
+ "classProxy.intercept(methodProxies[" + i + "], "
+ "originalInstance, "
+ "args"
+ ");\n";
}
str += "\treturn ret;\n";
} else {
str += "\tclassProxy.intercept(methodProxies[" + i + "], "
+ "originalInstance, "
+ "args"
+ ");\n";
}
str += "}";
cc.addMethod(CtMethod.make(str, cc));
}
// generate proxy instance
return (T)cc.toClass(classLoader, null).getConstructor(ClassProxy.class, clazz, MethodProxy[].class).newInstance(proxy, instance, methodProxies);
}
}