All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fireflysource.common.bytecode.JavassistReflectionProxyFactory Maven / Gradle / Ivy

There is a newer version: 5.0.2
Show newest version
package com.fireflysource.common.bytecode;

import com.fireflysource.common.string.StringUtils;
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() {

    }

    protected ArrayProxy createArrayProxy(Class clazz) {
        try {
            ClassPool classPool = ClassPool.getDefault();
            classPool.insertClassPath(new ClassClassPath(ArrayProxy.class));

            CtClass cc = classPool.makeClass("com.fireflysource.common.bytecode.ArrayField" + UUID.randomUUID().toString().replace("-", ""));
            cc.addInterface(classPool.get(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 (ArrayProxy) JavassistUtils.getClass(cc).getConstructor().newInstance();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private String createArraySetCode(Class clazz) {
        StringBuilder code = new StringBuilder("public void set(Object array, int index, Object value){\n");

        Class componentType = clazz.getComponentType();
        if (componentType.isPrimitive()) {
            String t = "\t(({})array)[index] = (({})value).{}Value();\n";
            code.append(StringUtils.replace(t,
                    clazz.getCanonicalName(),
                    primitiveWrapMap.get(componentType),
                    componentType.getCanonicalName()));
        } else {
            String t = "\t(({})array)[index] = ({})value;\n";
            code.append(StringUtils.replace(t, clazz.getCanonicalName(), componentType.getCanonicalName()));
        }

        code.append("}");
        return code.toString();
    }

    private String createArrayGetCode(Class clazz) {
        StringBuilder code = new StringBuilder("public Object get(Object array, int index){\n");

        Class componentType = clazz.getComponentType();
        if (componentType.isPrimitive()) {
            String t = "\treturn (Object){}.valueOf((({})array)[index]);\n";
            code.append(StringUtils.replace(t, primitiveWrapMap.get(componentType), clazz.getCanonicalName()));
        } else {
            String t = "\treturn (({})array)[index];\n";
            code.append(StringUtils.replace(t, clazz.getCanonicalName()));
        }

        code.append("}");
        return code.toString();
    }

    private String createArraySizeCode(Class clazz) {
        String t = "public int size(Object array){\n" +
                "\treturn (({})array).length;\n" +
                "}";
        return StringUtils.replace(t, clazz.getCanonicalName());
    }

    protected FieldProxy createFieldProxy(Field field) {
        try {
            ClassPool classPool = ClassPool.getDefault();
            classPool.insertClassPath(new ClassClassPath(FieldProxy.class));

            CtClass cc = classPool.makeClass("com.fireflysource.common.bytecode.ProxyField" + UUID.randomUUID().toString().replace("-", ""));
            cc.addInterface(classPool.get(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 (FieldProxy) JavassistUtils.getClass(cc).getConstructor(Field.class).newInstance(field);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private String createFieldGetterMethodCode(Field field) {
        Class fieldClazz = field.getType();
        StringBuilder code = new StringBuilder("public Object get(Object obj){\n");

        if (fieldClazz.isPrimitive()) {
            String t = "\treturn (Object){}.valueOf( (({})obj).{} );\n";
            code.append(StringUtils.replace(t,
                    primitiveWrapMap.get(fieldClazz),
                    field.getDeclaringClass().getCanonicalName(),
                    field.getName()));
        } else {
            String t = "\treturn (({})obj).{};\n";
            code.append(StringUtils.replace(t,
                    field.getDeclaringClass().getCanonicalName(),
                    field.getName()));
        }

        code.append("}");
        return code.toString();
    }

    private String createFieldSetterMethodCode(Field field) {
        Class fieldClazz = field.getType();
        StringBuilder code = new StringBuilder("public void set(Object obj, Object value){\n");

        if (fieldClazz.isPrimitive()) {
            String t = "\t(({})obj).{} = (({})value).{}Value();\n";
            code.append(StringUtils.replace(t,
                    field.getDeclaringClass().getCanonicalName(), field.getName(),
                    primitiveWrapMap.get(fieldClazz), fieldClazz.getCanonicalName()));
        } else {
            String t = "\t(({})obj).{} = ({})value;\n";
            code.append(StringUtils.replace(t,
                    field.getDeclaringClass().getCanonicalName(), field.getName(),
                    fieldClazz.getCanonicalName()));
        }

        code.append("}");
        return code.toString();
    }

    protected MethodProxy createMethodProxy(Method method) {
        try {
            ClassPool classPool = ClassPool.getDefault();
            classPool.insertClassPath(new ClassClassPath(MethodProxy.class));

            CtClass cc = classPool.makeClass("com.fireflysource.common.bytecode.ProxyMethod" + UUID.randomUUID().toString().replace("-", ""));

            cc.addInterface(classPool.get(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 (MethodProxy) JavassistUtils.getClass(cc).getConstructor(Method.class).newInstance(method);
        } catch (Exception e) {
            throw new IllegalStateException(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) {
            String t = "\tif(args == null || args.length != {})\n" +
                    "\t\tthrow new IllegalArgumentException(\"arguments error\");\n\n";
            code.append(StringUtils.replace(t, paramClazz.length));
        }
        if (method.getReturnType().equals(Void.TYPE)) {
            code.append('\t').append(createMethodCall(method)).append(";\n")
                .append("\treturn null;\n");
        } else {
            code.append("\treturn ");
            if (method.getReturnType().isPrimitive()) {
                code.append(StringUtils.replace("(Object){}.valueOf(", primitiveWrapMap.get(method.getReturnType())))
                    .append(createMethodCall(method))
                    .append(");\n");
            } else {
                code.append(createMethodCall(method)).append(";\n");
            }
        }

        code.append('}');
        return code.toString();
    }

    private String createMethodCall(Method method) {
        Class[] paramClazz = method.getParameterTypes();
        StringBuilder code = new StringBuilder();

        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(", ");
            }
        }
        code.append(')');
        return code.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy