Search in sources :

Example 21 with StringAppender

use of org.mvel2.util.StringAppender in project mvel by mikebrock.

the class ReflectiveAccessorOptimizer method getMethod.

/**
 * Find an appropriate method, execute it, and return it's response.
 *
 * @param ctx  -
 * @param name -
 * @return -
 * @throws Exception -
 */
@SuppressWarnings({ "unchecked" })
private Object getMethod(Object ctx, String name) throws Exception {
    int st = cursor;
    String tk = cursor != end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, '(')) - st) > 1 ? new String(expr, st + 1, cursor - st - 1) : "";
    cursor++;
    Object[] args;
    Class[] argTypes;
    ExecutableStatement[] es;
    if (tk.length() == 0) {
        args = ParseTools.EMPTY_OBJ_ARR;
        argTypes = ParseTools.EMPTY_CLS_ARR;
        es = null;
    } else {
        List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
        es = new ExecutableStatement[subtokens.size()];
        args = new Object[subtokens.size()];
        argTypes = new Class[subtokens.size()];
        for (int i = 0; i < subtokens.size(); i++) {
            try {
                args[i] = (es[i] = (ExecutableStatement) subCompileExpression(subtokens.get(i), pCtx)).getValue(this.thisRef, thisRef, variableFactory);
            } catch (CompileException e) {
                throw ErrorUtil.rewriteIfNeeded(e, this.expr, this.start);
            }
            if (es[i].isExplicitCast())
                argTypes[i] = es[i].getKnownEgressType();
        }
        if (pCtx.isStrictTypeEnforcement()) {
            for (int i = 0; i < args.length; i++) {
                argTypes[i] = es[i].getKnownEgressType();
            }
        } else {
            for (int i = 0; i < args.length; i++) {
                if (argTypes[i] != null)
                    continue;
                if (es[i].getKnownEgressType() == Object.class) {
                    argTypes[i] = args[i] == null ? null : args[i].getClass();
                } else {
                    argTypes[i] = es[i].getKnownEgressType();
                }
            }
        }
    }
    if (first && variableFactory != null && variableFactory.isResolveable(name)) {
        Object ptr = variableFactory.getVariableResolver(name).getValue();
        if (ptr instanceof Method) {
            ctx = ((Method) ptr).getDeclaringClass();
            name = ((Method) ptr).getName();
        } else if (ptr instanceof MethodStub) {
            ctx = ((MethodStub) ptr).getClassReference();
            name = ((MethodStub) ptr).getMethodName();
        } else if (ptr instanceof Function) {
            Function func = (Function) ptr;
            if (!name.equals(func.getName())) {
                getBeanProperty(ctx, name);
                addAccessorNode(new DynamicFunctionAccessor(es));
            } else {
                addAccessorNode(new FunctionAccessor((Function) ptr, es));
            }
            return ((Function) ptr).call(ctx, thisRef, variableFactory, args);
        } else {
            throw new OptimizationFailure("attempt to optimize a method call for a reference that does not point to a method: " + name + " (reference is type: " + (ctx != null ? ctx.getClass().getName() : null) + ")");
        }
        first = false;
    }
    if (ctx == null) {
        throw new PropertyAccessException("null pointer or function not found: " + name, this.expr, this.start);
    }
    boolean classTarget = false;
    Class<?> cls = currType != null ? currType : ((classTarget = ctx instanceof Class) ? (Class<?>) ctx : ctx.getClass());
    currType = null;
    Method m;
    Class[] parameterTypes = null;
    if ((m = getBestCandidate(argTypes, name, cls, cls.getMethods(), false, classTarget)) != null) {
        parameterTypes = m.getParameterTypes();
    }
    if (m == null && classTarget) {
        /**
         * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
         */
        if ((m = getBestCandidate(argTypes, name, cls, Class.class.getMethods(), false)) != null) {
            parameterTypes = m.getParameterTypes();
        }
    }
    if (m == null) {
        StringAppender errorBuild = new StringAppender();
        if ("size".equals(name) && args.length == 0 && cls.isArray()) {
            addAccessorNode(new ArrayLength());
            return getLength(ctx);
        }
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getClass().getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        throw new PropertyAccessException("unable to resolve method: " + cls.getName() + "." + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", this.expr, this.st);
    } else {
        if (es != null) {
            ExecutableStatement cExpr;
            for (int i = 0; i < es.length; i++) {
                cExpr = (ExecutableStatement) es[i];
                if (cExpr.getKnownIngressType() == null) {
                    cExpr.setKnownIngressType(parameterTypes[i]);
                    cExpr.computeTypeConversionRule();
                }
                if (!cExpr.isConvertableIngressEgress()) {
                    args[i] = convert(args[i], parameterTypes[i]);
                }
            }
        } else {
            /**
             * Coerce any types if required.
             */
            for (int i = 0; i < args.length; i++) args[i] = convert(args[i], parameterTypes[i]);
        }
        Object o = getWidenedTarget(m).invoke(ctx, args);
        if (hasNullMethodHandler()) {
            addAccessorNode(new MethodAccessorNH(getWidenedTarget(m), (ExecutableStatement[]) es, getNullMethodHandler()));
            if (o == null)
                o = getNullMethodHandler().getProperty(m.getName(), ctx, variableFactory);
        } else {
            addAccessorNode(new MethodAccessor(getWidenedTarget(m), (ExecutableStatement[]) es));
        }
        /**
         * return the response.
         */
        return o;
    }
}
Also used : ExecutableStatement(org.mvel2.compiler.ExecutableStatement) Function(org.mvel2.ast.Function)

Example 22 with StringAppender

use of org.mvel2.util.StringAppender in project mvel by mikebrock.

the class ObjectInspector method renderMethods.

private static void renderMethods(Class cls) {
    Method[] methods = cls.getMethods();
    Method m;
    StringAppender appender = new StringAppender();
    int mf;
    for (int i = 0; i < methods.length; i++) {
        appender.append(TextUtil.paint(' ', PADDING + 2));
        if (((mf = (m = methods[i]).getModifiers()) & Modifier.PUBLIC) != 0)
            appender.append("public");
        else if ((mf & Modifier.PRIVATE) != 0)
            appender.append("private");
        else if ((mf & Modifier.PROTECTED) != 0)
            appender.append("protected");
        appender.append(' ').append(m.getReturnType().getName()).append(' ').append(m.getName()).append("(");
        Class[] parmTypes = m.getParameterTypes();
        for (int y = 0; y < parmTypes.length; y++) {
            if (parmTypes[y].isArray()) {
                appender.append(parmTypes[y].getComponentType().getName() + "[]");
            } else {
                appender.append(parmTypes[y].getName());
            }
            if ((y + 1) < parmTypes.length)
                appender.append(", ");
        }
        appender.append(")");
        if (m.getDeclaringClass() != cls) {
            appender.append("    [inherited from: ").append(m.getDeclaringClass().getName()).append("]");
        }
        if ((i + 1) < methods.length)
            appender.append('\n');
    }
    System.out.println(appender.toString());
}
Also used : StringAppender(org.mvel2.util.StringAppender) Method(java.lang.reflect.Method)

Example 23 with StringAppender

use of org.mvel2.util.StringAppender in project mvel by mikebrock.

the class PropertyVerifier method getMethod.

/**
 * Process method
 *
 * @param ctx  - the ingress type
 * @param name - the property component
 * @return known egress type.
 */
private Class getMethod(Class ctx, String name) {
    int st = cursor;
    /**
     * Check to see if this is the first element in the statement.
     */
    if (first) {
        first = false;
        methodCall = true;
        /**
         * It's the first element in the statement, therefore we check to see if there is a static import of a
         * native Java method or an MVEL function.
         */
        if (pCtx.hasImport(name)) {
            Method m = pCtx.getStaticImport(name).getMethod();
            /**
             * Replace the method parameters.
             */
            ctx = m.getDeclaringClass();
            name = m.getName();
        } else if (pCtx.hasFunction(name)) {
            resolvedExternally = false;
            Function f = pCtx.getFunction(name);
            f.checkArgumentCount(parseParameterList((((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1 ? ParseTools.subset(expr, st + 1, cursor - st - 1) : new char[0]), 0, -1).size());
            return f.getEgressType();
        } else if (pCtx.hasVarOrInput("this")) {
            if (pCtx.isStrictTypeEnforcement()) {
                recordTypeParmsForProperty("this");
            }
            ctx = pCtx.getVarOrInputType("this");
            resolvedExternally = false;
        }
    }
    /**
     * Get the arguments for the method.
     */
    String tk;
    if (cursor < end && expr[cursor] == '(' && ((cursor = balancedCapture(expr, cursor, end, '(')) - st) > 1) {
        tk = new String(expr, st + 1, cursor - st - 1);
    } else {
        tk = "";
    }
    cursor++;
    /**
     * Parse out the arguments list.
     */
    Class[] args;
    List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
    if (subtokens.size() == 0) {
        args = new Class[0];
        subtokens = Collections.emptyList();
    } else {
        // ParserContext subCtx = pCtx.createSubcontext();
        args = new Class[subtokens.size()];
        /**
         *  Subcompile all the arguments to determine their known types.
         */
        // ExpressionCompiler compiler;
        List<ErrorDetail> errors = pCtx.getErrorList().isEmpty() ? pCtx.getErrorList() : new ArrayList<ErrorDetail>(pCtx.getErrorList());
        CompileException rethrow = null;
        for (int i = 0; i < subtokens.size(); i++) {
            try {
                args[i] = MVEL.analyze(subtokens.get(i), pCtx);
                if ("null".equals(String.valueOf(subtokens.get(i)))) {
                    args[i] = NullType.class;
                }
            } catch (CompileException e) {
                rethrow = ErrorUtil.rewriteIfNeeded(e, expr, this.st);
            }
            if (errors.size() < pCtx.getErrorList().size()) {
                for (ErrorDetail detail : pCtx.getErrorList()) {
                    if (!errors.contains(detail)) {
                        detail.setExpr(expr);
                        detail.setCursor(new String(expr).substring(this.st).indexOf(new String(subtokens.get(i))) + this.st);
                        detail.setColumn(0);
                        detail.setLineNumber(0);
                        detail.calcRowAndColumn();
                    }
                }
            }
            if (rethrow != null) {
                throw rethrow;
            }
        }
    }
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    Method m;
    if ((m = getBestCandidate(args, name, ctx, ctx.getMethods(), pCtx.isStrongTyping())) == null) {
        if ((m = getBestCandidate(args, name, ctx, ctx.getDeclaredMethods(), pCtx.isStrongTyping())) == null) {
            StringAppender errorBuild = new StringAppender();
            for (int i = 0; i < args.length; i++) {
                errorBuild.append(args[i] != null ? args[i].getName() : null);
                if (i < args.length - 1)
                    errorBuild.append(", ");
            }
            if (("size".equals(name) || "length".equals(name)) && args.length == 0 && ctx.isArray()) {
                return Integer.class;
            }
            if (pCtx.isStrictTypeEnforcement()) {
                throw new CompileException("unable to resolve method using strict-mode: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")", expr, tkStart);
            }
            return Object.class;
        }
    }
    /**
     * If we're in strict mode, we look for generic type information.
     */
    if (pCtx.isStrictTypeEnforcement() && m.getGenericReturnType() != null) {
        Map<String, Class> typeArgs = new HashMap<String, Class>();
        Type[] gpt = m.getGenericParameterTypes();
        Class z;
        ParameterizedType pt;
        for (int i = 0; i < gpt.length; i++) {
            if (gpt[i] instanceof ParameterizedType) {
                pt = (ParameterizedType) gpt[i];
                if ((z = pCtx.getImport(new String(subtokens.get(i)))) != null) {
                    /**
                     * We record the value of the type parameter to our typeArgs Map.
                     */
                    if (pt.getRawType().equals(Class.class)) {
                        /**
                         * If this is an instance of Class, we deal with the special parameterization case.
                         */
                        typeArgs.put(pt.getActualTypeArguments()[0].toString(), z);
                    } else {
                        typeArgs.put(gpt[i].toString(), z);
                    }
                }
            }
        }
        if (pCtx.isStrictTypeEnforcement() && ctx.getTypeParameters().length != 0 && pCtx.getLastTypeParameters() != null && pCtx.getLastTypeParameters().length == ctx.getTypeParameters().length) {
            TypeVariable[] typeVariables = ctx.getTypeParameters();
            for (int i = 0; i < typeVariables.length; i++) {
                typeArgs.put(typeVariables[i].getName(), (Class) pCtx.getLastTypeParameters()[i]);
            }
        }
        /**
         * Get the return type argument
         */
        Type parametricReturnType = m.getGenericReturnType();
        String returnTypeArg = parametricReturnType.toString();
        // push return type parameters onto parser context, only if this is a parametric type
        if (parametricReturnType instanceof ParameterizedType) {
            pCtx.setLastTypeParameters(((ParameterizedType) parametricReturnType).getActualTypeArguments());
        }
        if (paramTypes != null && paramTypes.containsKey(returnTypeArg)) {
            /**
             * If the paramTypes Map contains the known type, return that type.
             */
            return (Class) paramTypes.get(returnTypeArg);
        } else if (typeArgs.containsKey(returnTypeArg)) {
            /**
             * If the generic type was declared as part of the method, it will be in this
             * Map.
             */
            return typeArgs.get(returnTypeArg);
        }
    }
    if (!Modifier.isPublic(m.getModifiers())) {
        StringAppender errorBuild = new StringAppender();
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        String scope = Modifier.toString(m.getModifiers());
        if (scope.trim().equals(""))
            scope = "<package local>";
        addFatalError("the referenced method is not accessible: " + ctx.getName() + "." + name + "(" + errorBuild.toString() + ")" + " (scope: " + scope + "; required: public", this.tkStart);
    }
    return m.getReturnType();
}
Also used : Function(org.mvel2.ast.Function) NullType(org.mvel2.util.NullType) StringAppender(org.mvel2.util.StringAppender)

Example 24 with StringAppender

use of org.mvel2.util.StringAppender in project mvel by mikebrock.

the class PropertyAccessor method getMethod.

/**
 * Find an appropriate method, execute it, and return it's response.
 *
 * @param ctx  -
 * @param name -
 * @return -
 * @throws Exception -
 */
@SuppressWarnings({ "unchecked" })
private Object getMethod(Object ctx, String name) {
    int _start = cursor;
    String tk = cursor != end && property[cursor] == '(' && ((cursor = balancedCapture(property, cursor, '(')) - _start) > 1 ? new String(property, _start + 1, cursor - _start - 1) : "";
    cursor++;
    Object[] args;
    if (tk.length() == 0) {
        args = ParseTools.EMPTY_OBJ_ARR;
    } else {
        List<char[]> subtokens = parseParameterList(tk.toCharArray(), 0, -1);
        args = new Object[subtokens.size()];
        for (int i = 0; i < subtokens.size(); i++) {
            args[i] = eval(subtokens.get(i), thisReference, variableFactory);
        }
    }
    if (first && variableFactory != null && variableFactory.isResolveable(name)) {
        Object ptr = variableFactory.getVariableResolver(name).getValue();
        if (ptr instanceof Method) {
            ctx = ((Method) ptr).getDeclaringClass();
            name = ((Method) ptr).getName();
        } else if (ptr instanceof MethodStub) {
            ctx = ((MethodStub) ptr).getClassReference();
            name = ((MethodStub) ptr).getMethodName();
        } else if (ptr instanceof Function) {
            ((Function) ptr).checkArgumentCount(args.length);
            return ((Function) ptr).call(null, thisReference, variableFactory, args);
        } else {
            throw new OptimizationFailure("attempt to optimize a method call for a reference that does not point to a method: " + name + " (reference is type: " + (ctx != null ? ctx.getClass().getName() : null) + ")");
        }
        first = false;
    }
    if (ctx == null)
        throw new CompileException("no such method or function: " + name, property, cursor);
    /**
     * If the target object is an instance of java.lang.Class itself then do not
     * adjust the Class scope target.
     */
    Class cls = (ctx instanceof Class ? (Class) ctx : ctx.getClass());
    if (cls == Proto.ProtoInstance.class) {
        return ((Proto.ProtoInstance) ctx).get(name).call(null, thisReference, variableFactory, args);
    }
    /**
     * Check to see if we have already cached this method;
     */
    Object[] cache = checkMethodCache(cls, createSignature(name, tk));
    Method m;
    Class[] parameterTypes;
    if (cache != null) {
        m = (Method) cache[0];
        parameterTypes = (Class[]) cache[1];
    } else {
        m = null;
        parameterTypes = null;
    }
    /**
     * If we have not cached the method then we need to go ahead and try to resolve it.
     */
    if (m == null) {
        /**
         * Try to find an instance method from the class target.
         */
        if ((m = getBestCandidate(args, name, cls, cls.getMethods(), false)) != null) {
            addMethodCache(cls, createSignature(name, tk), m);
            parameterTypes = m.getParameterTypes();
        }
        if (m == null) {
            /**
             * If we didn't find anything, maybe we're looking for the actual java.lang.Class methods.
             */
            if ((m = getBestCandidate(args, name, cls, cls.getClass().getDeclaredMethods(), false)) != null) {
                addMethodCache(cls, createSignature(name, tk), m);
                parameterTypes = m.getParameterTypes();
            }
        }
    }
    if (m == null) {
        StringAppender errorBuild = new StringAppender();
        for (int i = 0; i < args.length; i++) {
            errorBuild.append(args[i] != null ? args[i].getClass().getName() : null);
            if (i < args.length - 1)
                errorBuild.append(", ");
        }
        if ("size".equals(name) && args.length == 0 && cls.isArray()) {
            return getLength(ctx);
        }
        System.out.println("{ " + new String(property) + " }");
        throw new PropertyAccessException("unable to resolve method: " + cls.getName() + "." + name + "(" + errorBuild.toString() + ") [arglength=" + args.length + "]", property, st);
    } else {
        for (int i = 0; i < args.length; i++) {
            args[i] = convert(args[i], parameterTypes[i]);
        }
        /**
         * Invoke the target method and return the response.
         */
        try {
            return m.invoke(ctx, args);
        } catch (IllegalAccessException e) {
            try {
                addMethodCache(cls, createSignature(name, tk), (m = getWidenedTarget(m)));
                return m.invoke(ctx, args);
            } catch (Exception e2) {
                throw new PropertyAccessException("unable to invoke method: " + name, property, cursor, e2);
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new PropertyAccessException("unable to invoke method: " + name, property, cursor, e);
        }
    }
}
Also used : Function(org.mvel2.ast.Function) Proto(org.mvel2.ast.Proto) MethodStub(org.mvel2.util.MethodStub) StringAppender(org.mvel2.util.StringAppender)

Example 25 with StringAppender

use of org.mvel2.util.StringAppender in project mvel by mikebrock.

the class MacroProcessor method parse.

public char[] parse(char[] input) {
    setExpression(input);
    StringAppender appender = new StringAppender();
    int start;
    boolean macroArmed = true;
    String token;
    for (; cursor < length; cursor++) {
        start = cursor;
        while (cursor < length && isIdentifierPart(expr[cursor])) cursor++;
        if (cursor > start) {
            if (macros.containsKey(token = new String(expr, start, cursor - start)) && macroArmed) {
                appender.append(macros.get(token).doMacro());
            } else {
                appender.append(token);
            }
        }
        if (cursor < length) {
            switch(expr[cursor]) {
                case '\\':
                    cursor++;
                    break;
                case '/':
                    start = cursor;
                    if (cursor + 1 != length) {
                        switch(expr[cursor + 1]) {
                            case '/':
                                while (cursor != length && expr[cursor] != '\n') cursor++;
                                break;
                            case '*':
                                int len = length - 1;
                                while (cursor != len && !(expr[cursor] == '*' && expr[cursor + 1] == '/')) cursor++;
                                cursor += 2;
                                break;
                        }
                    }
                    if (cursor < length)
                        cursor++;
                    appender.append(new String(expr, start, cursor - start));
                    if (cursor < length)
                        cursor--;
                    break;
                case '"':
                case '\'':
                    appender.append(new String(expr, (start = cursor), (cursor = captureStringLiteral(expr[cursor], expr, cursor, length)) - start));
                    if (cursor >= length)
                        break;
                    else if (isIdentifierPart(expr[cursor]))
                        cursor--;
                default:
                    switch(expr[cursor]) {
                        case '.':
                            macroArmed = false;
                            break;
                        case ';':
                        case '{':
                        case '(':
                            macroArmed = true;
                            break;
                    }
                    appender.append(expr[cursor]);
            }
        }
    }
    return appender.toChars();
}
Also used : StringAppender(org.mvel2.util.StringAppender)

Aggregations

StringAppender (org.mvel2.util.StringAppender)37 Test (org.junit.Test)13 MethodVisitor (org.mvel2.asm.MethodVisitor)6 Method (java.lang.reflect.Method)5 CompileException (org.mvel2.CompileException)5 ClassWriter (org.mvel2.asm.ClassWriter)4 Function (org.mvel2.ast.Function)4 MethodStub (org.mvel2.util.MethodStub)4 HashMap (java.util.HashMap)3 ExecutableStatement (org.mvel2.compiler.ExecutableStatement)3 IOException (java.io.IOException)2 DecimalFormat (java.text.DecimalFormat)2 LinkedList (java.util.LinkedList)2 Random (java.util.Random)2 ErrorDetail (org.mvel2.ErrorDetail)2 OptimizationFailure (org.mvel2.OptimizationFailure)2 ParserContext (org.mvel2.ParserContext)2 ScriptRuntimeException (org.mvel2.ScriptRuntimeException)2 UnresolveablePropertyException (org.mvel2.UnresolveablePropertyException)2 FunctionInstance (org.mvel2.ast.FunctionInstance)2