package com.firefly.utils.classproxy; import com.firefly.utils.ReflectUtils; import com.firefly.utils.StringUtils; import com.firefly.utils.exception.CommonRuntimeException; import javassist.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.UUID; /** * @author Pengtao Qiu */ public class JavassistReflectionProxyFactory extends AbstractProxyFactory { public static final JavassistReflectionProxyFactory INSTANCE = new JavassistReflectionProxyFactory(); private JavassistReflectionProxyFactory() { } @SuppressWarnings("unchecked") protected ReflectUtils.ArrayProxy _getArrayProxy(Class<?> clazz) { try { ClassPool classPool = ClassPool.getDefault(); classPool.insertClassPath(new ClassClassPath(ReflectUtils.ArrayProxy.class)); CtClass cc = classPool.makeClass("com.firefly.utils.ArrayField" + UUID.randomUUID().toString().replace("-", "")); cc.addInterface(classPool.get(ReflectUtils.ArrayProxy.class.getName())); cc.addMethod(CtMethod.make(createArraySizeCode(clazz), cc)); cc.addMethod(CtMethod.make(createArrayGetCode(clazz), cc)); cc.addMethod(CtMethod.make(createArraySetCode(clazz), cc)); return (ReflectUtils.ArrayProxy) cc.toClass(classLoader, null).getConstructor().newInstance(); } catch (Exception e) { throw new CommonRuntimeException(e); } } private String createArraySetCode(Class<?> clazz) { StringBuilder code = new StringBuilder(); code.append("public void set(Object array, int index, Object value){\n") .append(StringUtils.replace("\t(({})array)[index] = ", clazz.getCanonicalName())); Class<?> componentType = clazz.getComponentType(); if (componentType.isPrimitive()) { code.append(StringUtils.replace("(({})value).{}Value()", primitiveWrapMap.get(componentType), componentType.getCanonicalName())); } else { code.append(StringUtils.replace("({})value", componentType.getCanonicalName())); } code.append(";\n") .append("}"); return code.toString(); } private String createArrayGetCode(Class<?> clazz) { StringBuilder code = new StringBuilder(); code.append("public Object get(Object array, int index){\n") .append("\treturn "); Class<?> componentType = clazz.getComponentType(); boolean hasValueOf = false; if (componentType.isPrimitive()) { code.append(StringUtils.replace("(Object){}.valueOf(", primitiveWrapMap.get(componentType))); hasValueOf = true; } code.append(StringUtils.replace("(({})array)[index]", clazz.getCanonicalName())); if (hasValueOf) code.append(")"); code.append(";\n") .append("}"); return code.toString(); } private String createArraySizeCode(Class<?> clazz) { StringBuilder code = new StringBuilder(); code.append("public int size(Object array){\n") .append("\treturn ").append(StringUtils.replace("(({})array).length;\n", clazz.getCanonicalName())) .append("}"); return code.toString(); } @SuppressWarnings("unchecked") protected ReflectUtils.FieldProxy _getFieldProxy(Field field) { try { ClassPool classPool = ClassPool.getDefault(); classPool.insertClassPath(new ClassClassPath(ReflectUtils.FieldProxy.class)); CtClass cc = classPool.makeClass("com.firefly.utils.ProxyField" + UUID.randomUUID().toString().replace("-", "")); cc.addInterface(classPool.get(ReflectUtils.FieldProxy.class.getName())); cc.addField(CtField.make("private java.lang.reflect.Field field;", cc)); CtConstructor constructor = new CtConstructor(new CtClass[]{classPool.get(Field.class.getName())}, cc); constructor.setBody("{this.field = (java.lang.reflect.Field)$1;}"); cc.addConstructor(constructor); cc.addMethod(CtMethod.make("public java.lang.reflect.Field field(){return field;}", cc)); cc.addMethod(CtMethod.make(createFieldGetterMethodCode(field), cc)); cc.addMethod(CtMethod.make(createFieldSetterMethodCode(field), cc)); return (ReflectUtils.FieldProxy) cc.toClass(classLoader, null).getConstructor(Field.class).newInstance(field); } catch (Exception e) { throw new CommonRuntimeException(e); } } private String createFieldGetterMethodCode(Field field) { Class<?> fieldClazz = field.getType(); StringBuilder code = new StringBuilder(); code.append("public Object get(Object obj){\n") .append("\treturn "); boolean hasValueOf = false; if (fieldClazz.isPrimitive()) { code.append(StringUtils.replace("(Object){}.valueOf(", primitiveWrapMap.get(fieldClazz))); hasValueOf = true; } code.append(StringUtils.replace("(({})obj).{}", field.getDeclaringClass().getCanonicalName(), field.getName())); if (hasValueOf) code.append(")"); code.append(";\n") .append("}"); return code.toString(); } private String createFieldSetterMethodCode(Field field) { Class<?> fieldClazz = field.getType(); StringBuilder code = new StringBuilder(); code.append("public void set(Object obj, Object value){\n"); code.append(StringUtils.replace("\t(({})obj).{} = ", field.getDeclaringClass().getCanonicalName(), field.getName())); if (fieldClazz.isPrimitive()) { code.append(StringUtils.replace("(({})value).{}Value()", primitiveWrapMap.get(fieldClazz), fieldClazz.getCanonicalName())); } else { code.append(StringUtils.replace("({})value", fieldClazz.getCanonicalName())); } code.append(";\n") .append("}"); return code.toString(); } @SuppressWarnings("unchecked") protected ReflectUtils.MethodProxy _getMethodProxy(Method method) { try { ClassPool classPool = ClassPool.getDefault(); classPool.insertClassPath(new ClassClassPath(ReflectUtils.MethodProxy.class)); CtClass cc = classPool.makeClass("com.firefly.utils.ProxyMethod" + UUID.randomUUID().toString().replace("-", "")); cc.addInterface(classPool.get(ReflectUtils.MethodProxy.class.getName())); cc.addField(CtField.make("private java.lang.reflect.Method method;", cc)); CtConstructor constructor = new CtConstructor(new CtClass[]{classPool.get(Method.class.getName())}, cc); constructor.setBody("{this.method = (java.lang.reflect.Method)$1;}"); cc.addConstructor(constructor); cc.addMethod(CtMethod.make("public java.lang.reflect.Method method(){return method;}", cc)); cc.addMethod(CtMethod.make(createInvokeMethodCode(method), cc)); return (ReflectUtils.MethodProxy) cc.toClass(classLoader, null).getConstructor(Method.class).newInstance(method); } catch (Exception e) { throw new CommonRuntimeException(e); } } private String createInvokeMethodCode(Method method) { Class<?>[] paramClazz = method.getParameterTypes(); StringBuilder code = new StringBuilder(); code.append("public Object invoke(Object obj, Object[] args){\n "); if (paramClazz.length > 0) code.append('\t') .append(StringUtils.replace("if(args == null || args.length != {})", paramClazz.length)) .append("\n\t\t") .append("throw new IllegalArgumentException(\"arguments error\");\n") .append('\n'); boolean hasValueOf = false; code.append('\t'); if (!method.getReturnType().equals(Void.TYPE)) { code.append("return "); if (method.getReturnType().isPrimitive()) { code.append(StringUtils.replace("(Object){}.valueOf(", primitiveWrapMap.get(method.getReturnType()))); hasValueOf = true; } } if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) code.append(method.getDeclaringClass().getCanonicalName()); else code.append(StringUtils.replace("(({})obj)", method.getDeclaringClass().getCanonicalName())); code.append('.').append(method.getName()).append('('); if (paramClazz.length > 0) { int max = paramClazz.length - 1; for (int i = 0; ; i++) { Class<?> param = paramClazz[i]; if (param.isPrimitive()) { code.append(StringUtils.replace("(({})args[{}]).{}Value()", primitiveWrapMap.get(param), i, param.getCanonicalName())); } else { code.append(StringUtils.replace("({})args[{}]", param.getCanonicalName(), i)); } if (i == max) { break; } code.append(", "); } } if (hasValueOf) { code.append(")"); } code.append(");\n"); if (method.getReturnType().equals(Void.TYPE)) { code.append("\treturn null;\n"); } code.append('}'); return code.toString(); } }