Package com.dp4j.processors.core

Source Code of com.dp4j.processors.core.PrivateAccessProcessor

package com.dp4j.processors.core;

import com.dp4j.InjectReflection;
import com.dp4j.ast.Node;
import com.dp4j.ast.Resolver;
import com.dp4j.processors.DProcessor;
import com.sun.source.tree.*;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import java.util.*;
import java.util.ArrayList;
import javax.lang.model.type.*;
import javax.tools.Diagnostic.Kind.*;
import org.apache.commons.lang.*;
import com.sun.tools.javac.util.Name;
import com.sun.source.tree.Scope;
import com.sun.source.tree.Tree;

/**
*
* @author simpatico
*/
@SupportedAnnotationTypes(value = {"org.junit.Test", "com.dp4j.InjectReflection", "org.testng.annotations.Test"})
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class PrivateAccessProcessor extends DProcessor {

    public Type getType(Symbol s) {
        Type t;
        if (s instanceof MethodSymbol) {
            t = ((MethodSymbol) s).getReturnType();
        } else {
            t = s.type;
        }
        return t;
    }

    @Override
    protected void processElement(Element e, TypeElement ann, boolean warningsOnly) {
        if (options.containsKey("conservative")) {
            if (!ann.getQualifiedName().toString().equals(InjectReflection.class.getCanonicalName())) {
                return;
            }
        }

        encClass = (TypeElement) e.getEnclosingElement();
        PackageElement packageOf = elementUtils.getPackageOf(e);
        List<? extends Element> pkgClasses = packageOf.getEnclosedElements();

        rs = new Resolver(elementUtils, trees, tm, encClass, typeUtils, symTable, pkgClasses);

        final JCMethodDecl tree = (JCMethodDecl) elementUtils.getTree(e);

        thisExp = tm.This((Type) encClass.asType());

        final TreePath treePath = trees.getPath(e);
        final CompilationUnitTree cut = treePath.getCompilationUnit();
        tree.body = processElement(tree.body, cut, tree);

        if (reflectionInjected || methodInjected || constructorInjected) {
            tree.thrown = tree.thrown.append(getId("java.lang.ClassNotFoundException"));
            tree.thrown = tree.thrown.append(getId("java.lang.NoSuchFieldException"));
            tree.thrown = tree.thrown.append(getId("java.lang.IllegalAccessException"));
            if (constructorInjected || methodInjected) {
                tree.thrown = tree.thrown.append(getId("java.lang.NoSuchMethodException"));
                tree.thrown = tree.thrown.append(getId("java.lang.reflect.InvocationTargetException"));
                if (constructorInjected) {
                    tree.thrown = tree.thrown.append(getId("java.lang.InstantiationException"));
                    constructorInjected = false;
                }
            }
            if (methodInjected) {
                tree.thrown = tree.thrown.append(getId("java.lang.IllegalArgumentException"));
                methodInjected = false;
            }
            reflectionInjected = false;
        }
        printVerbose(cut, e);
    }
    boolean constructorInjected = false;

    protected JCBlock processElement(final JCBlock tree, final CompilationUnitTree cut, Scope validScope) {
        if (tree == null) return null;
        for (Tree stmt : tree.stats) {
            validScope = getScope(stmt, cut, validScope);
            Node n = new Node(validScope, stmt);
            tree.stats = (com.sun.tools.javac.util.List<JCStatement>) processStmt(n, cut, tree);
            if (tree.stats.indexOf(stmt) < tree.stats.size() - 1) {
                validScope = trees.getScope(trees.getPath(cut, stmt));
            }
        }
        return tree;
    }

    private Scope getScope(Tree stmt, final CompilationUnitTree cut, Scope validScope) {
        if (stmt instanceof JCVariableDecl) {
            JCExpression exp = ((JCVariableDecl) stmt).init;
            ((JCVariableDecl) stmt).init = null;
            TreePath path = TreePath.getPath(cut, stmt);
            validScope = trees.getScope(path);
            ((JCVariableDecl) stmt).init = exp;
        } else if (stmt instanceof JCEnhancedForLoop) {
            return getScope(((JCEnhancedForLoop) stmt).var, cut, validScope);
        } else if (stmt instanceof JCForLoop) {
            return getScope(((JCForLoop) stmt).init.last(), cut, validScope);
        }
        return validScope;
    }

    protected JCBlock processElement(BlockTree tree, final CompilationUnitTree cut, Tree getScope) {
        if(tree == null) return null;
        TreePath path = trees.getPath(cut, getScope);
        return processElement((JCBlock) tree, cut, trees.getScope(path));
    }


    protected BlockTree blockify(StatementTree stmt){
        if(stmt == null) return null;
        if(stmt instanceof  BlockTree) return (BlockTree) stmt;
        return tm.Block(0l, com.sun.tools.javac.util.List.of((JCStatement)stmt));
    }

    /**
     * @param stmt
     * @param vars
     * @param cut
     * @param packageName
     * @param scope
     * @param stats required for injecting reflection statements globally, and also when not possible locally, eg. if-expr
     * @param varSyms
     * @return
     */
    protected com.sun.tools.javac.util.List<? extends Tree> processStmt(Node n, final CompilationUnitTree cut, JCBlock encBlock) {
        final Tree stmt = n.actual;
        if (stmt instanceof JCVariableDecl) {
            JCVariableDecl varDec = (JCVariableDecl) stmt;
            boolean accessible = isAccessible(varDec.init, cut, n);
            if (!accessible) {
                ((JCVariableDecl) stmt).init = processCond(varDec.init, cut, n, encBlock);
                Symbol s = rs.getSymbol(varDec.init, cut, n);
                final Type t = getType(s);
                varDec.sym = (VarSymbol) rs.getSymbol(cut, n, null, varDec.name, null);
                varDec.type = varDec.sym.type;
                if (varDec.init.type == null) {
                    varDec.init.type = varDec.sym.type;
                }
                if (differentArg(t, varDec.sym.type)) {
                    varDec.init = tm.TypeCast(rs.getBoxedType(varDec.sym), varDec.init);
                }
            }
        } else if (stmt instanceof JCTry) {
            JCTry tryStmt = (JCTry) stmt;
            if (tryStmt.body != null && tryStmt.body.stats != null && !tryStmt.body.stats.isEmpty()) {
                tryStmt.body = processElement(tryStmt.body, cut, n.scope);
            }
            List<JCCatch> catchers = tryStmt.catchers;
            for (JCCatch jCCatch : catchers) {
                if (jCCatch.body != null && jCCatch.body.stats != null && !jCCatch.body.stats.isEmpty()) {
                    jCCatch.body = processElement(jCCatch.body, cut, jCCatch.param);
                }
            }
                        if (tryStmt.finalizer != null && tryStmt.finalizer.stats != null && !tryStmt.finalizer.stats.isEmpty()) {
                tryStmt.finalizer = processElement(tryStmt.finalizer, cut, n.scope);
            }

        } else if (stmt instanceof JCIf) {
            JCIf ifStmt = (JCIf) stmt;
            ifStmt.cond = processCond(ifStmt.cond, cut, n, encBlock);
            ifStmt.thenpart = (JCStatement) blockify(ifStmt.thenpart);
            ifStmt.thenpart = processElement((JCBlock)ifStmt.thenpart, cut, ifStmt.cond);
            ifStmt.elsepart = (JCStatement) blockify(ifStmt.elsepart);
            ifStmt.elsepart = processElement((JCBlock)ifStmt.elsepart, cut, ifStmt.cond);
            //hanlde else!!, note that JCBlock is an instance of JCStatement, generalize ProcessElement to receive to accept stmts and if not block them and then process as usual

        } else if (stmt instanceof JCExpressionStatement) {
            JCExpressionStatement expStmt = (JCExpressionStatement) stmt;
            expStmt.expr = processCond(expStmt.expr, cut, n, encBlock);
        } else if (stmt instanceof JCBlock) {
            n.actual = processElement((JCBlock) stmt, cut, n.scope);
        } else if (stmt instanceof JCWhileLoop) {
            JCWhileLoop loop = (JCWhileLoop) stmt;
            loop.cond = processCond(loop.cond, cut, n, encBlock);
            loop.body = (JCStatement) blockify(loop.body);
            loop.body = processElement((JCBlock) loop.body, cut, n.scope);
        } else if (stmt instanceof JCForLoop) {
            JCForLoop loop = (JCForLoop) stmt;
            loop.cond = processCond(loop.cond, cut, n, encBlock);
            loop.body = (JCStatement) blockify(loop.body);
            loop.body = processElement((JCBlock) loop.body, cut, loop.cond);
        } else if (stmt instanceof JCDoWhileLoop) {
            JCDoWhileLoop loop = (JCDoWhileLoop) stmt;
            loop.cond = processCond(loop.cond, cut, n, encBlock);
loop.body = (JCStatement) blockify(loop.body);
            loop.body = processElement(((JCBlock) loop.body), cut, n.scope);
        } else if (stmt instanceof JCEnhancedForLoop) {
            JCEnhancedForLoop loop = (JCEnhancedForLoop) stmt;
            boolean accessible = isAccessible(loop.expr, cut, n);
            if (!accessible) {
                loop.expr = processCond(loop.expr, cut, n, encBlock);
                loop.var.sym = (VarSymbol) rs.getSymbol(cut, n, null, loop.var.name, null);
                final Symbol s = rs.getSymbol(loop.expr, cut, n);
                final Type t = getType(s);
                ArrayType arrayType = typeUtils.getArrayType(loop.var.sym.type);
                if (differentArg(t, (Type) arrayType)) {
                    loop.expr = tm.TypeCast((Type) arrayType, loop.expr);
                }
            }
            loop.body = (JCStatement) blockify(loop.body);
            loop.body = processElement((JCBlock) loop.body, cut, loop.expr);
        }
        return encBlock.stats;
    }

    protected JCExpression processCond(JCExpression ifExp, final CompilationUnitTree cut, Node n, JCBlock encBlock) {
        if (ifExp instanceof JCFieldAccess) {
            final JCFieldAccess fa = (JCFieldAccess) ifExp;
            final boolean accessible = isAccessible(fa, cut, n);
            if (!accessible) {
                Symbol s = rs.getSymbol(ifExp, cut, n);
                reflect(s, cut, n, null, encBlock);
                final JCExpression accessor;
                if (s.isStatic()) {
                    accessor = tm.Literal(StringUtils.EMPTY);
                } else {
                    accessor = fa.selected;
                }
                ifExp = getReflectedAccess(fa, cut, n, null, accessor);
                reflectionInjected = true;
            }
        } else if (ifExp instanceof JCMethodInvocation) {
            JCMethodInvocation mi = (JCMethodInvocation) ifExp;
            final MethodSymbol mSym = rs.getSymbol(mi, cut, n);
            if (!mi.args.isEmpty()) {
                for (JCExpression arg : mi.args) {
                    JCExpression newArg = processCond(arg, cut, n, encBlock);
                    if (!newArg.equals(arg)) {
                        mi.args = Resolver.injectBefore(arg, mi.args, true, newArg);
                    }
                }
            }
            Symbol accSym = rs.getInvokationTarget(mi, cut, n);
            final boolean accessible = isAccessible(mSym, accSym, cut, n);
            if (!accessible) {
                ifExp.type = mSym.getReturnType();
                reflect(mSym, cut, n, mi.args, encBlock);
                JCExpression accessor = rs.getInvokationExp(mi, cut, n);
                ifExp = getReflectedAccess(mSym, cut, accessor, mi.args, n);
                methodInjected = true;
            } else {
                ifExp.type = mSym.getReturnType();
            }
        } else if (ifExp instanceof JCNewClass) {
            JCNewClass init = (JCNewClass) ifExp;
            Symbol initSym = rs.getSymbol(ifExp, cut, n);
            if (!init.args.isEmpty()) {
                for (JCExpression arg : init.args) {
                    JCExpression newArg = processCond(arg, cut, n, encBlock);
                    if (!newArg.equals(arg)) {
                        init.args = rs.injectBefore(arg, init.args, true, newArg);
                    }
                }
            }
            final boolean accessible = isAccessible(initSym, initSym.enclClass(), cut, n);
            ifExp.type = rs.getType(initSym);
            if (!accessible) {
                reflect(initSym, cut, n, init.args, encBlock);
                ifExp = getReflectedAccess(initSym, cut, null, init.args, n);
                constructorInjected = true;
            }
            ifExp.type = rs.getType(initSym);
        } else if (ifExp instanceof JCTypeCast) {
            JCTypeCast cast = (JCTypeCast) ifExp;
            cast.expr = processCond(cast.expr, cut, n, encBlock);

        } else if (ifExp instanceof JCParens) {
            JCParens parensExp = (JCParens) ifExp;
            parensExp.expr = processCond(parensExp.expr, cut, n, encBlock);
            ifExp.type = parensExp.expr.type;
        } else if (ifExp instanceof JCLiteral) {
            ifExp.type = rs.getType((JCLiteral) ifExp);
        } else if (ifExp instanceof JCIdent) {
            Symbol symbol = rs.getSymbol(ifExp, cut, n);
            ifExp.type = symbol.type;
        } else if (ifExp instanceof JCBinary) {
            JCBinary ifB = (JCBinary) ifExp;
//            if (ifB.lhs instanceof JCFieldAccess) {
//                final JCFieldAccess fa = (JCFieldAccess) ifB.lhs;
            ifB.rhs = processCond(ifB.rhs, cut, n, encBlock);

            final boolean accessible = isAccessible(ifB.lhs, cut, n);
            if (!accessible) {
                ifB.lhs = processCond(ifB.lhs, cut, n, encBlock);
                Symbol s = rs.getSymbol(ifB.lhs, cut, n);
                final Type t = getType(s);
                if (!typeUtils.getNullType().equals(ifB.rhs.type)) {
                    if (differentArg(t, ifB.rhs.type)) {
                        ifB.lhs = tm.Parens(tm.TypeCast(rs.getBoxedType(ifB.rhs.type), ifB.lhs));
                    }
                }
            }
//            }

//            if (ifB.rhs instanceof JCFieldAccess) {
//                final JCFieldAccess fa = (JCFieldAccess) ifB.rhs;
//                final boolean accessible = isAccessible(fa, cut, stmt);
//                if (!accessible) {
//                    Symbol s = rs.getSymbol(fa, cut, stmt);
//                    encBlock.stats = reflect(s, cut, encBlock.stats, stmt);
//                    ifB.rhs = cast(getReflectedAccess(fa, cut, stmt, null, varSyms, fa.selected), rs.getBoxedType(s));
//                    reflectionInjected = true;
//                }
//            }
        } else if (ifExp instanceof JCAssign) {
            JCAssign assignExp = (JCAssign) ifExp;
            if (!isAccessible(assignExp.rhs, cut, n)) {
                final Type rhsTypeBeforeReflection = rs.getType(assignExp.rhs, cut, n);
                final JCMethodInvocation reflectedAccess = (JCMethodInvocation) processCond(assignExp.rhs, cut, n, encBlock);
                assignExp.rhs = cast(reflectedAccess, rhsTypeBeforeReflection);
            }
            if (assignExp.lhs instanceof JCFieldAccess) {
                final JCFieldAccess fa = (JCFieldAccess) assignExp.lhs;
                final boolean accessible = isAccessible(fa, cut, n);
                if (!accessible) {
                    Symbol s = rs.getSymbol(fa, cut, n);
                    reflect(s, cut, n, null, encBlock);
                    JCMethodInvocation reflectedFieldSetter = getReflectedFieldSetter(fa, assignExp.rhs, cut, n);
                    ifExp = reflectedFieldSetter;
                }
            }
        } else if (ifExp instanceof JCArrayAccess) {
            //TODO: reflect array
        } else if (ifExp.type == null) {
//            ifExp.type = getType(ifExp, vars, cut, packageName, scope, stmt, args, varSyms);
        }
        return ifExp;
    }

    public boolean isAccessible(JCMethodInvocation mi, CompilationUnitTree cut, Node n) {
        Symbol s = rs.getSymbol(mi, cut, n);
        Symbol accessor = rs.getInvokationTarget(mi, cut, n);
        return isAccessible(s, accessor, cut, n);
    }

    public boolean isAccessible(JCFieldAccess fa, CompilationUnitTree cut, Node n) {
        Symbol s = rs.getSymbol(fa, cut, n);
        Symbol accessor = rs.getAccessor(fa, cut, n);
        return isAccessible(s, accessor, cut, n);
    }

    public boolean isAccessible(JCExpression exp, CompilationUnitTree cut, Node n) {
        Symbol s = rs.getSymbol(exp, cut, n);
        Symbol accessor = null;
        if (exp instanceof JCFieldAccess) {
            accessor = rs.getAccessor((JCFieldAccess) exp, cut, n);
        } else if (exp instanceof JCMethodInvocation) {
            accessor = rs.getInvokationTarget((JCMethodInvocation) exp, cut, n);
        } else if (exp instanceof JCPrimitiveTypeTree) {
            return true;
        } else if (exp instanceof JCNewArray) {
            JCNewArray arr = (JCNewArray) exp;
            boolean accessible = true;
            if (arr.elems != null) {
                for (JCExpression el : arr.elems) {
                    accessible &= isAccessible(el, cut, n);
                    if (!accessible) {
                        break;
                    }
                }
            }
            return accessible;
        } else if (exp instanceof JCLiteral) {
            return true;
        } else if (exp instanceof JCParens) {
            return isAccessible(((JCParens) exp).expr, cut, n);
        } else if (exp instanceof JCTypeCast) {
            return isAccessible(((JCTypeCast) exp).expr, cut, n);
        } else if (exp instanceof JCNewClass) {
            accessor = rs.getSymbol(((JCNewClass) exp).clazz, cut, n); //retrieve the class symbol, as it's considered to be the accessor of the constructor
        } else if (exp instanceof JCBinary) {
            JCBinary bin = (JCBinary) exp;
            return isAccessible(bin.lhs, cut, n) && isAccessible(bin.rhs, cut, n);
        } else if (exp instanceof JCIdent) {
            if (((VarSymbol) s).isLocal()) {
                return true;
            }
            accessor = (Symbol) encClass;
        } else if (exp instanceof JCAssign) {
            JCAssign assign = (JCAssign) exp;
            return isAccessible(assign.lhs, cut, n) && isAccessible(assign.rhs, cut, n);
        } else if (exp instanceof JCArrayAccess) {
            if (((JCArrayAccess) exp).indexed instanceof JCFieldAccess) {
                accessor = rs.getAccessor((JCFieldAccess) ((JCArrayAccess) exp).indexed, cut, n);
            } else {
                return isAccessible(((JCArrayAccess) exp).indexed, cut, n);
            }
        }
        if (accessor == null || s == null) {
            throw new RuntimeException("is this accessible " + exp);
        }
        return isAccessible(s, accessor, cut, n);
    }

    public boolean isAccessible(Symbol s, final Symbol accessor, CompilationUnitTree cut, Node n) {
        final DeclaredType itd;
        if (accessor instanceof MethodSymbol) {
            itd = (DeclaredType) ((MethodSymbol) accessor).getReturnType();
        } else {
            if (accessor.type instanceof ArrayType) {
                return rs.getSymbol(s.name, accessor, cut, n) != null;//FIXME: what about args? But we already have the symbol!
            } else {
                itd = (DeclaredType) accessor.type;
            }
        }
        return trees.isAccessible(n.scope, s, itd);
    }

    protected void reflect(Symbol s, final CompilationUnitTree cut, Node n, com.sun.tools.javac.util.List<JCExpression> args, JCBlock encBlock) {
        final java.util.List<? extends Symbol> params;
        final Name accesseeVarName;

        if (s instanceof MethodSymbol) {
            if (s.isConstructor()) {
                accesseeVarName = getConstructorVar(s.owner.name, ((MethodSymbol)s).params);
            } else {
                accesseeVarName = getMethodVar(s.name, ((MethodSymbol)s).params);
            }
            final com.sun.tools.javac.util.List<TypeSymbol> formalTypeParams = ((MethodSymbol) s).getTypeParameters();
            if (formalTypeParams.isEmpty()) {
                params = ((MethodSymbol) s).params;
            } else {
                params = rs.getArgs(args, cut, n);
            }
        } else {
            accesseeVarName = getFieldVar(s.name);
            params = Collections.EMPTY_LIST;
        }
        reflect(s, cut, params, n, encBlock, accesseeVarName);
    }

    public void reflect(Symbol symbol, CompilationUnitTree cut, List<? extends Symbol> params, Node n, JCBlock encBlock, Name accesseeVarName) {
        ClassSymbol cs = (ClassSymbol) symbol.owner;
        JCIdent typeId = tm.Ident(cs.fullname); //"com.dp4j.samples.RPrivateArrayMethod"

        //getClass var
        MethodSymbol javaLangClassSym = (MethodSymbol) rs.getSymbol(elementUtils.getName(clazz), cs, cut, n);

        JCIdent javaLangClassId = tm.Ident(javaLangClassSym.getReturnType().tsym);
        //        Name classVarName = getClassVarName(className);
        JCExpression forNameAccessor = tm.Select(javaLangClassId, javaLangClassSym.name);
        JCExpression className = tm.Literal(typeId.toString());
        JCMethodInvocation classGetter = tm.Apply(com.sun.tools.javac.util.List.<JCExpression>nil(), forNameAccessor, com.sun.tools.javac.util.List.<JCExpression>of(className));
//        JCVariableDecl classDecl = tm.VarDef(tm.Modifiers(Flags.FINAL), classVarName, javaLangClassId, classGetter);

        JCExpression[] types = getTypes(params);
        final com.sun.tools.javac.util.List<JCExpression> args;

        final JCExpression javaReflectMethField;
        final Name getterName;
        if (symbol instanceof MethodSymbol) {
            if (symbol.isConstructor()) {
                getterName = elementUtils.getName("getDeclaredConstructor");
                javaReflectMethField = getIdAfterImporting("java.lang.reflect.Constructor");
                args = toList(types);
            } else {
                getterName = elementUtils.getName("getDeclaredMethod");
                javaReflectMethField = getIdAfterImporting("java.lang.reflect.Method");
                JCExpression mName = tm.Literal(symbol.name.toString());
                args = merge(Collections.singleton(mName), toList(types));
            }
        } else {
            getterName = elementUtils.getName("getDeclaredField");
            javaReflectMethField = getIdAfterImporting("java.lang.reflect.Field");
            args = com.sun.tools.javac.util.List.<JCExpression>of(tm.Literal(symbol.name.toString()));
        }

        Symbol fieldMethSym = rs.getSymbol(cut, n, null, accesseeVarName, null);
        if (fieldMethSym == null) {
            final JCExpression getMethField = tm.Select(classGetter, getterName);
            JCMethodInvocation mi = tm.Apply(com.sun.tools.javac.util.List.<JCExpression>nil(), getMethField, args);
            final JCVariableDecl refDecl = tm.VarDef(tm.Modifiers(Flags.FINAL), accesseeVarName, javaReflectMethField, mi);
            final JCMethodInvocation setAccInvoc = getMethodInvoc(accesseeVarName + ".setAccessible", true);
            JCStatement setAccessibleExec = tm.Exec(setAccInvoc); //should there be a dereflect / or just setinaccessible just after access? Would be better to set true only at access/set time and set-false after it. So reflect injects only one stmt while access/set 3
            JCStatement[] refStmts = new JCStatement[2];

            if (refDecl != null) {
                refStmts[0] = refDecl;
                refStmts[1] = setAccessibleExec;
                encBlock.stats = injectBefore((JCStatement) n.actual, encBlock.stats, refStmts);
                TreePath refPath = trees.getPath(cut, refStmts[1]);
                n.scope = getScope(n.actual, cut, trees.getScope(refPath));
            }

            reflectionInjected = true;
        }
    }

    JCMethodInvocation getReflectedAccess(JCFieldAccess fa, final CompilationUnitTree cut, Node n, com.sun.tools.javac.util.List<JCExpression> args, JCExpression accessor) {
        final Symbol s = rs.getSymbol(fa, cut, n);
        return getReflectedAccess(s, cut, accessor, args, n);
    }

    /**
     *
     * @param s
     * @param cut
     * @param accessor assumed to be accessible. TODO: get rid of assumption!
     * @param args
     * @return
     */
    JCMethodInvocation getReflectedAccess(Symbol s, final CompilationUnitTree cut, JCExpression accessor, com.sun.tools.javac.util.List<JCExpression> args, Node n) {
        final Name getterName;
        final JCIdent fieldMethInitId;
        if (s instanceof MethodSymbol) {
            if (s.isConstructor()) {
                getterName = elementUtils.getName("newInstance");
                fieldMethInitId = tm.Ident(getConstructorVar(s.owner.name, ((MethodSymbol)s).params));
            } else {
                getterName = elementUtils.getName("invoke");

                fieldMethInitId = tm.Ident(getMethodVar(s.name, ((MethodSymbol) s).params));
            }

            if (((MethodSymbol) s).isVarArgs()) {
                int i = 0;
                VarSymbol last = ((MethodSymbol) s).params.last();
                Type varArgType = (Type) ((ArrayType) last.asType()).getComponentType();
                com.sun.tools.javac.util.List<JCExpression> reverse = args.reverse();
                for (JCExpression arg : reverse) {
                    Symbol argSym = rs.getSymbol(arg, cut, n);
                    Type type = getType(argSym);
                    if (differentArg(type, varArgType)) {
                        break;
                    } else {
                        i++;
                    }
                }
                final int varArgEnd = args.size();
                final int varArgIndex = varArgEnd - i;
                java.util.List<JCExpression> varArgs = args.subList(varArgIndex, varArgEnd);
                JCNewArray varArgArray = getArray(varArgType, varArgs);
                List<JCExpression> otherArgs = args.subList(0, varArgIndex);
                List<JCExpression> arrayList = new ArrayList<JCExpression>();
                arrayList.add(varArgArray);
                args = merge(otherArgs, arrayList);
            }
            if (args.size() > 0) {
                Type t = elementUtils.getTypeElement("java.lang.Object").type;
                args = com.sun.tools.javac.util.List.<JCExpression>of(getArray(t, args));
            }
            if (!s.isConstructor()) {
                args = merge(Collections.singleton(accessor), args);
            }
        } else {
            fieldMethInitId = tm.Ident(getFieldVar(s.name));
            getterName = elementUtils.getName("get"); //TODO: for type safety replace with primitive concatenation
            args = com.sun.tools.javac.util.List.<JCExpression>of(accessor);
        }

        final JCExpression getMethField = tm.Select(fieldMethInitId, getterName);
        JCMethodInvocation mi = tm.Apply(com.sun.tools.javac.util.List.<JCExpression>nil(), getMethField, args);
        reflectionInjected = true; //call this method to actually use it!

        return mi;
    }

    JCMethodInvocation getReflectedFieldSetter(JCFieldAccess fa, final JCExpression value, final CompilationUnitTree cut, Node n) {
        final Name field = getFieldVar(fa.name);
        Symbol s = rs.getSymbol(value, cut, n);
        s = rs.getTypeSymbol(s);
        String typeName = s.name.toString();
        typeName = StringUtils.capitalize(typeName);
        JCMethodInvocation set = getMethodInvoc(field + ".set" + typeName, fa.selected, value);
        return set;
    }

    Name getFieldVar(final Name objName) {
        return elementUtils.getName(objName + "Field");
    }

    Name getMethodVar(Name objName, List<? extends Symbol> params) {
        return getVar(objName, params, "Method");
    }

    Name getVar(Name objName, List<? extends Symbol> params, final String varType){
       String with = params.isEmpty() ? StringUtils.EMPTY : "With";

       with += StringUtils.join(getNames(params), "And");
        return elementUtils.getName(objName + with + varType);
    }

    Name getConstructorVar(Name initName, List<? extends Symbol> params) {
        initName = rs.getName(initName);
        initName = elementUtils.getName(StringUtils.uncapitalize(initName.toString()));
        return getVar(initName, params, "Constructor");
    }

    List<Name> getNames(List<? extends Symbol> params){
        List<Name> names = new ArrayList<Name>();
        for (Symbol symbol : params) {
            final Symbol ts = rs.getTypeSymbol(symbol);
            final Name n;
            if(ts instanceof ArrayType){
                String toString = ((ArrayType)ts).getComponentType().toString();
                n = elementUtils.getName(toString + ts.getSimpleName());
            }else{
                n = ts.getSimpleName();
            }
            names.add(n);
        }
        return names;
    }

    boolean reflectionInjected = false;
    boolean methodInjected = false;

    /**
     * Junit or someone else might want to handle it
     * @return
     */
    @Override
    protected boolean onlyHandler(Set<? extends TypeElement> annotations) {
        if (annotations.size() == 1) {
            TypeElement next = annotations.iterator().next();
            if (next.getQualifiedName().toString().equals(InjectReflection.class.getCanonicalName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * One thing you can't do under any circumstance is cast from an object to a primitive data type, or vice versa.
     * http://www.informit.com/articles/article.aspx?p=30871&seqNum=5
     * @param reflectedAccess
     * @param t
     * @return
     */
    JCParens cast(JCMethodInvocation reflectedAccess, Type t) {
        return tm.Parens(tm.TypeCast(rs.getBoxedType(t), reflectedAccess));
    }
}
TOP

Related Classes of com.dp4j.processors.core.PrivateAccessProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.