You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by he...@apache.org on 2015/08/27 22:06:54 UTC

svn commit: r1698224 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/ main/java/org/apache/commons/jexl3/internal/ test/java/org/apache/commons/jexl3/

Author: henrib
Date: Thu Aug 27 20:06:53 2015
New Revision: 1698224

URL: http://svn.apache.org/r1698224
Log:
JEXL:
Fix JEXL-171: revisited resolution strategies, use operator to resolve, allow custom resolver implementation and usage
Fix JEXL-174: related to above, arithmetic can define method to overload operator resolution (array{G,S}et, property{G,S}et
Fix JEXL-173: objects exposing a 'call' method can be used as function calls (ie foo(x) will perform foo.call(x))

Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlOperator.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java Thu Aug 27 20:06:53 2015
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl3;
 
 import org.apache.commons.jexl3.introspection.JexlMethod;
+
 import java.lang.reflect.Array;
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -128,21 +129,12 @@ public class JexlArithmetic {
         boolean overloads(JexlOperator operator);
 
         /**
-         * Gets the most specific method for a monadic operator.
-         * @param operator the operator
-         * @param arg      the argument
-         * @return the most specific method or null if no specific override could be found
-         */
-        JexlMethod getOperator(JexlOperator operator, Object arg);
-
-        /**
-         * Gets the most specific method for a diadic operator.
+         * Gets the most specific method for an operator.
          * @param operator the operator
-         * @param lhs      the left hand side argument
-         * @param rhs      the right hand side argument
+         * @param arg      the arguments
          * @return the most specific method or null if no specific override could be found
          */
-        JexlMethod getOperator(JexlOperator operator, Object lhs, Object rhs);
+        JexlMethod getOperator(JexlOperator operator, Object... arg);
     }
 
     /**

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlBuilder.java Thu Aug 27 20:06:53 2015
@@ -67,9 +67,9 @@ public class JexlBuilder {
      */
     protected JexlUberspect uberspect = null;
     /**
-     * The resolver strategy.
+     * The strategy strategy.
      */
-    protected JexlUberspect.ResolverStrategy resolver = null;
+    protected JexlUberspect.ResolverStrategy strategy = null;
     /**
      * The sandbox.
      */
@@ -132,19 +132,19 @@ public class JexlBuilder {
     }
 
     /**
-     * Sets the JexlUberspect resolver strategy the engine will use.
+     * Sets the JexlUberspect strategy strategy the engine will use.
      * <p>This is ignored if the uberspect has been set.
      * @param rs the strategy
      * @return this builder
      */
     public JexlBuilder strategy(JexlUberspect.ResolverStrategy rs) {
-        this.resolver = rs;
+        this.strategy = rs;
         return this;
     }
 
-    /** @return the resolver strategy */
+    /** @return the strategy strategy */
     public JexlUberspect.ResolverStrategy strategy() {
-        return this.resolver;
+        return this.strategy;
     }
 
     /**

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlOperator.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlOperator.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlOperator.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlOperator.java Thu Aug 27 20:06:53 2015
@@ -205,7 +205,23 @@ public enum JexlOperator {
      * <br/>Returns this from 'self*' overload method to let the engine know the side effect has been performed and
      * there is no need to assign the result.
      */
-    ASSIGN("=", null, null);
+    ASSIGN("=", null, null),
+    /**
+     * Property get operator as in: x.y.
+     */
+    PROPERTY_GET(".", "propertyGet", 2),
+    /**
+     * Property set operator as in: x.y = z.
+     */
+    PROPERTY_SET(".=", "propertySet", 3),
+    /**
+     * Array get operator as in: x[y].
+     */
+    ARRAY_GET("[]", "arrayGet", 2),
+    /**
+     * Array set operator as in: x[y] = z.
+     */
+    ARRAY_SET("[]=", "arraySet", 3);
     /**
      * The operator symbol.
      */

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/JexlScript.java Thu Aug 27 20:06:53 2015
@@ -45,6 +45,13 @@ public interface JexlScript {
     String getParsedText();
 
     /**
+     * Recreates the source text of this expression from the internal syntactic tree.
+     * @param indent the number of spaces for indentation, 0 meaning no indentation
+     * @return the source text
+     */
+    String getParsedText(int indent);
+
+    /**
      * Executes the script with the variables contained in the
      * supplied {@link JexlContext}.
      *

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java Thu Aug 27 20:06:53 2015
@@ -22,10 +22,13 @@ import org.apache.commons.jexl3.JexlCont
 import org.apache.commons.jexl3.JexlEngine;
 import org.apache.commons.jexl3.JexlException;
 import org.apache.commons.jexl3.JexlScript;
+
 import org.apache.commons.jexl3.introspection.JexlMethod;
 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
 import org.apache.commons.jexl3.introspection.JexlPropertySet;
 import org.apache.commons.jexl3.introspection.JexlUberspect;
+import org.apache.commons.jexl3.introspection.JexlUberspect.PropertyResolver;
+
 import org.apache.commons.jexl3.parser.ASTAddNode;
 import org.apache.commons.jexl3.parser.ASTAndNode;
 import org.apache.commons.jexl3.parser.ASTArguments;
@@ -57,6 +60,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.ASTIfStatement;
 import org.apache.commons.jexl3.parser.ASTJexlLambda;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.parser.ASTJxltLiteral;
 import org.apache.commons.jexl3.parser.ASTLENode;
 import org.apache.commons.jexl3.parser.ASTLTNode;
 import org.apache.commons.jexl3.parser.ASTMapEntry;
@@ -98,6 +102,7 @@ import org.apache.commons.jexl3.parser.A
 import org.apache.commons.jexl3.parser.JexlNode;
 import org.apache.commons.jexl3.parser.Node;
 import org.apache.commons.jexl3.parser.ParserVisitor;
+import org.apache.commons.jexl3.parser.StringParser;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -300,7 +305,7 @@ public class Interpreter extends ParserV
             throw new JexlException.Property(node, var, cause);
         }
         if (!silent) {
-            logger.warn(JexlException.propertyError(node, var));
+            logger.warn(JexlException.propertyError(node, var), cause);
         }
         return null;
     }
@@ -318,7 +323,7 @@ public class Interpreter extends ParserV
                 throw new JexlException.Operator(node, operator.getOperatorSymbol(), cause);
             }
             if (!silent) {
-                logger.warn(JexlException.operatorError(node, operator.getOperatorSymbol()));
+                logger.warn(JexlException.operatorError(node, operator.getOperatorSymbol()), cause);
             }
         }
     }
@@ -1479,12 +1484,19 @@ public class Interpreter extends ParserV
                         }
                     }
                 }
-                // lambda, script or jexl method will do
-                if (functor instanceof JexlScript) {
-                    return ((JexlScript) functor).execute(context, argv);
-                }
-                if (functor instanceof JexlMethod) {
-                    return ((JexlMethod) functor).invoke(bean, argv);
+                if (functor != null) {
+                    // lambda, script or jexl method will do
+                    if (functor instanceof JexlScript) {
+                        return ((JexlScript) functor).execute(context, argv);
+                    }
+                    if (functor instanceof JexlMethod) {
+                        return ((JexlMethod) functor).invoke(bean, argv);
+                    }
+                    // a generic callable
+                    vm = uberspect.getMethod(functor, "call", argv);
+                    if (vm != null) {
+                        return vm.invoke(functor, argv);
+                    }
                 }
                 // if we did not find an exact method by name and we haven't tried yet,
                 // attempt to narrow the parameters and if this succeeds, try again in next loop
@@ -1590,21 +1602,6 @@ public class Interpreter extends ParserV
     }
 
     /**
-     * Determines the property {s,g}etter strategy to use.
-     * @param node the syntactic node
-     * @param obj the instance we are seeking the {s,g}etter from
-     * @return a list of resolvers, not null
-     */
-    protected List<JexlUberspect.ResolverType> getPropertyResolvers(JexlNode node, Object obj) {
-        List<JexlUberspect.ResolverType> strategy = node == null
-                                                    ? null
-                                                    : node.jjtGetParent() instanceof ASTArrayAccess
-                                                    ? JexlUberspect.MAP
-                                                    : JexlUberspect.POJO;
-        return strategy;
-    }
-
-    /**
      * Gets an attribute of an object.
      *
      * @param object    to retrieve value from
@@ -1630,6 +1627,12 @@ public class Interpreter extends ParserV
         if (isCancelled()) {
             throw new JexlException.Cancel(node);
         }
+        final JexlOperator operator = node != null && node.jjtGetParent() instanceof ASTArrayAccess
+                                    ? JexlOperator.ARRAY_GET : JexlOperator.PROPERTY_GET;
+        Object result = operators.tryOverload(node, operator, object, attribute);
+        if (result != JexlEngine.TRY_FAILED) {
+            return result;
+        }
         // attempt to reuse last executor cached in volatile JexlNode.value
         if (node != null && cache) {
             Object cached = node.jjtGetValue();
@@ -1643,8 +1646,8 @@ public class Interpreter extends ParserV
         }
         // resolve that property
         Exception xcause = null;
-        List<JexlUberspect.ResolverType> strategy = getPropertyResolvers(node, object);
-        JexlPropertyGet vg = uberspect.getPropertyGet(strategy, object, attribute);
+        List<PropertyResolver> resolvers = uberspect.getResolvers(operator, object);
+        JexlPropertyGet vg =  uberspect.getPropertyGet(resolvers, object, attribute);
         if (vg != null) {
             try {
                 Object value = vg.invoke(object);
@@ -1693,6 +1696,12 @@ public class Interpreter extends ParserV
         if (isCancelled()) {
             throw new JexlException.Cancel(node);
         }
+        final JexlOperator operator = node != null && node.jjtGetParent() instanceof ASTArrayAccess
+                                    ? JexlOperator.ARRAY_SET : JexlOperator.PROPERTY_SET;
+        Object result = operators.tryOverload(node, operator, object, attribute, value);
+        if (result != JexlEngine.TRY_FAILED) {
+            return;
+        }
         // attempt to reuse last executor cached in volatile JexlNode.value
         if (node != null && cache) {
             Object cached = node.jjtGetValue();
@@ -1705,14 +1714,14 @@ public class Interpreter extends ParserV
             }
         }
         Exception xcause = null;
-        List<JexlUberspect.ResolverType> strategy = getPropertyResolvers(node, object);
-        JexlPropertySet vs = uberspect.getPropertySet(strategy, object, attribute, value);
+        List<PropertyResolver> resolvers = uberspect.getResolvers(operator, object);
+        JexlPropertySet vs = uberspect.getPropertySet(resolvers, object, attribute, value);
         // if we can't find an exact match, narrow the value argument and try again
         if (vs == null) {
             // replace all numbers with the smallest type that will fit
             Object[] narrow = {value};
             if (arithmetic.narrowArguments(narrow)) {
-                vs = uberspect.getPropertySet(strategy, object, attribute, narrow[0]);
+                vs = uberspect.getPropertySet(resolvers, object, attribute, narrow[0]);
             }
         }
         if (vs != null) {
@@ -1740,4 +1749,18 @@ public class Interpreter extends ParserV
             throw new UnsupportedOperationException(error, xcause);
         }
     }
+
+    @Override
+    protected Object visit(ASTJxltLiteral node, Object data) {
+        TemplateEngine.TemplateExpression tp = (TemplateEngine.TemplateExpression) node.jjtGetValue();
+        if (tp == null) {
+           TemplateEngine jxlt = jexl.jxlt();
+           tp = jxlt.parseExpression(node.jexlInfo(), node.getLiteral(), frame != null? frame.getScope() : null);
+           node.jjtSetValue(tp);
+        }
+        if (tp != null) {
+           return tp.evaluate(frame, context);
+        }
+        return null;
+    }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Operators.java Thu Aug 27 20:06:53 2015
@@ -59,15 +59,15 @@ public class Operators {
     }
 
     /**
-     * Attempts to call a monadic operator.
+     * Attempts to call an operator.
      * <p>
      * This takes care of finding and caching the operator method when appropriate
      * @param node     the syntactic node
      * @param operator the operator
-     * @param arg      the argument
+     * @param args     the arguments
      * @return the result of the operator evaluation or TRY_FAILED
      */
-    protected Object tryOverload(JexlNode node, JexlOperator operator, Object arg) {
+    protected Object tryOverload(JexlNode node, JexlOperator operator, Object... args) {
         if (operators != null && operators.overloads(operator)) {
             final JexlArithmetic arithmetic = interpreter.arithmetic;
             final boolean cache = interpreter.cache;
@@ -75,58 +75,18 @@ public class Operators {
                 Object cached = node.jjtGetValue();
                 if (cached instanceof JexlMethod) {
                     JexlMethod me = (JexlMethod) cached;
-                    Object eval = me.tryInvoke(operator.getMethodName(), arithmetic, arg);
+                    Object eval = me.tryInvoke(operator.getMethodName(), arithmetic, args);
                     if (!me.tryFailed(eval)) {
                         return eval;
                     }
                 }
             }
             try {
-                JexlMethod emptym = operators.getOperator(operator, arg);
-                if (emptym != null) {
-                    Object result = emptym.invoke(arithmetic, arg);
+                JexlMethod vm = operators.getOperator(operator, args);
+                if (vm != null) {
+                    Object result = vm.invoke(arithmetic, args);
                     if (cache) {
-                        node.jjtSetValue(emptym);
-                    }
-                    return result;
-                }
-            } catch (Exception xany) {
-                interpreter.operatorError(node, operator, xany);
-            }
-        }
-        return JexlEngine.TRY_FAILED;
-    }
-
-    /**
-     * Attempts to call a diadic operator.
-     * <p>
-     * This takes care of finding and caching the operator method when appropriate
-     * @param node     the syntactic node
-     * @param operator the operator
-     * @param lhs      the left hand side argument
-     * @param rhs      the right hand side argument
-     * @return the result of the operator evaluation or TRY_FAILED
-     */
-    protected Object tryOverload(JexlNode node, JexlOperator operator, Object lhs, Object rhs) {
-        if (operators != null && operators.overloads(operator)) {
-            final JexlArithmetic arithmetic = interpreter.arithmetic;
-            final boolean cache = interpreter.cache;
-            if (cache) {
-                Object cached = node.jjtGetValue();
-                if (cached instanceof JexlMethod) {
-                    JexlMethod me = (JexlMethod) cached;
-                    Object eval = me.tryInvoke(operator.getMethodName(), arithmetic, lhs, rhs);
-                    if (!me.tryFailed(eval)) {
-                        return eval;
-                    }
-                }
-            }
-            try {
-                JexlMethod emptym = operators.getOperator(operator, lhs, rhs);
-                if (emptym != null) {
-                    Object result = emptym.invoke(arithmetic, lhs, rhs);
-                    if (cache) {
-                        node.jjtSetValue(emptym);
+                        node.jjtSetValue(vm);
                     }
                     return result;
                 }
@@ -146,14 +106,16 @@ public class Operators {
      * </p>
      * @param node     the syntactic node
      * @param operator the operator
-     * @param lhs      the left hand side, target of the side-effect
-     * @param rhs      the right hand side, argument of the (base) operator
+     * @param args     the arguments, the first one being the target of assignment
      * @return the result of the operator evaluation
      */
-    protected Object tryAssignOverload(JexlNode node, JexlOperator operator, Object lhs, Object rhs) {
+    protected Object tryAssignOverload(JexlNode node, JexlOperator operator, Object...args) {
         final JexlArithmetic arithmetic = interpreter.arithmetic;
+        if (args.length != operator.getArity()) {
+            return JexlEngine.TRY_FAILED;
+        }
         // try to call overload on side effect
-        Object result = tryOverload(node, operator, lhs, rhs);
+        Object result = tryOverload(node, operator, args);
         if (result != JexlEngine.TRY_FAILED) {
             return result;
         }
@@ -165,9 +127,9 @@ public class Operators {
         if (operators != null && operators.overloads(base)) {
             // in case there is an overload
             try {
-                JexlMethod emptym = operators.getOperator(base, lhs, rhs);
-                if (emptym != null) {
-                    result = emptym.invoke(arithmetic, lhs, rhs);
+                JexlMethod vm = operators.getOperator(base, args);
+                if (vm != null) {
+                    result = vm.invoke(arithmetic, args);
                     if (result != JexlEngine.TRY_FAILED) {
                         return result;
                     }
@@ -179,21 +141,21 @@ public class Operators {
         // base eval
         switch (operator) {
             case SELF_ADD:
-                return arithmetic.add(lhs, rhs);
+                return arithmetic.add(args[0], args[1]);
             case SELF_SUBTRACT:
-                return arithmetic.subtract(lhs, rhs);
+                return arithmetic.subtract(args[0], args[1]);
             case SELF_MULTIPLY:
-                return arithmetic.multiply(lhs, rhs);
+                return arithmetic.multiply(args[0], args[1]);
             case SELF_DIVIDE:
-                return arithmetic.divide(lhs, rhs);
+                return arithmetic.divide(args[0], args[1]);
             case SELF_MOD:
-                return arithmetic.mod(lhs, rhs);
+                return arithmetic.mod(args[0], args[1]);
             case SELF_AND:
-                return arithmetic.and(lhs, rhs);
+                return arithmetic.and(args[0], args[1]);
             case SELF_OR:
-                return arithmetic.or(lhs, rhs);
+                return arithmetic.or(args[0], args[1]);
             case SELF_XOR:
-                return arithmetic.xor(lhs, rhs);
+                return arithmetic.xor(args[0], args[1]);
             default:
                 throw new JexlException.Operator(node, operator.getOperatorSymbol(), null);
         }
@@ -294,7 +256,7 @@ public class Operators {
      * the JEXL operator arguments order syntax is the reverse of this method call.
      * </p>
      * @param node  the node
-     * @param op    the calling operator, =~ or !=
+     * @param op    the calling operator, =~ or !~
      * @param right the left operand
      * @param left  the right operand
      * @return true if left matches right, false otherwise
@@ -338,22 +300,23 @@ public class Operators {
     /**
      * Check for emptyness of various types: Collection, Array, Map, String, and anything that has a boolean isEmpty()
      * method.
+     * <p>Note that the result may not be a boolean.
      *
      * @param node   the node holding the object
-     * @param object the object to check the emptyness of.
-     * @return the boolean
+     * @param object the object to check the emptyness of
+     * @return the evaluation result
      */
-    protected Boolean empty(JexlNode node, Object object) {
-        final JexlArithmetic arithmetic = interpreter.arithmetic;
-        final JexlUberspect uberspect = interpreter.uberspect;
+    protected Object empty(JexlNode node, Object object) {
         if (object == null) {
             return Boolean.TRUE;
         }
-        Object opcall = Operators.this.tryOverload(node, JexlOperator.EMPTY, object);
-        if (opcall instanceof Boolean) {
-            return (Boolean) opcall;
+        final JexlArithmetic arithmetic = interpreter.arithmetic;
+        final JexlUberspect uberspect = interpreter.uberspect;
+        Object result = Operators.this.tryOverload(node, JexlOperator.EMPTY, object);
+        if (result != JexlEngine.TRY_FAILED) {
+            return result;
         }
-        Boolean result = arithmetic.isEmpty(object);
+        result = arithmetic.isEmpty(object);
         if (result == null) {
             result = false;
             // check if there is an isEmpty method on the object that returns a
@@ -373,22 +336,23 @@ public class Operators {
     /**
      * Calculate the <code>size</code> of various types:
      * Collection, Array, Map, String, and anything that has a int size() method.
+     * <p>Note that the result may not be an integer.
      *
      * @param node   the node that gave the value to size
      * @param object the object to get the size of.
-     * @return the size of val
+     * @return the evaluation result
      */
-    protected Integer size(JexlNode node, Object object) {
-        final JexlArithmetic arithmetic = interpreter.arithmetic;
-        final JexlUberspect uberspect = interpreter.uberspect;
+    protected Object size(JexlNode node, Object object) {
         if (object == null) {
             return 0;
         }
-        Object opcall = Operators.this.tryOverload(node, JexlOperator.SIZE, object);
-        if (opcall instanceof Integer) {
-            return (Integer) opcall;
+        final JexlArithmetic arithmetic = interpreter.arithmetic;
+        final JexlUberspect uberspect = interpreter.uberspect;
+        Object result = Operators.this.tryOverload(node, JexlOperator.SIZE, object);
+        if (result != JexlEngine.TRY_FAILED) {
+            return result;
         }
-        Integer result = arithmetic.size(object);
+        result = arithmetic.size(object);
         if (result == null) {
             // check if there is a size method on the object that returns an
             // integer and if so, just use it

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/Script.java Thu Aug 27 20:06:53 2015
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl3.internal;
 
 import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
 import org.apache.commons.jexl3.JexlScript;
 import org.apache.commons.jexl3.JexlExpression;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
@@ -90,8 +91,14 @@ public class Script implements JexlScrip
     }
 
     /**
-     * Gets this script original script source.
-     * @return the contents of the input source as a String.
+     * @return the engine that created this script
+     */
+    public JexlEngine getEngine() {
+        return jexl;
+    }
+
+    /**
+     * {@inheritDoc}
      */
     @Override
     public String getSourceText() {
@@ -99,12 +106,20 @@ public class Script implements JexlScrip
     }
 
     /**
-     * Gets a string representation of this script underlying AST.
-     * @return the script as text
+     * {@inheritDoc}
      */
     @Override
     public String getParsedText() {
+        return getParsedText(2);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getParsedText(int indent) {
         Debugger debug = new Debugger();
+        debug.setIndentation(indent);
         debug.debug(script);
         return debug.toString();
     }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/LambdaTest.java Thu Aug 27 20:06:53 2015
@@ -45,7 +45,7 @@ public class LambdaTest extends JexlTest
     public void testScriptContext() throws Exception {
         JexlEngine jexl = new Engine();
         JexlScript s = jexl.createScript("function(x) { x + x }");
-        String fsstr = s.getParsedText();
+        String fsstr = s.getParsedText(0);
         Assert.assertEquals("(x)->{ x + x; }", fsstr);
         Assert.assertEquals(42, s.execute(null, 21));
         JexlScript s42 = jexl.createScript("s(21)");

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/SideEffectTest.java Thu Aug 27 20:06:53 2015
@@ -330,6 +330,29 @@ public class SideEffectTest extends Jexl
         Assert.assertEquals(3115L ^ 15,  v7.value);
     }
 
+
+    @Test
+    public void testOverrideGetSet() throws Exception {
+        JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new SelfArithmetic(false)).create();
+        JexlContext jc = null;
+
+        JexlScript script;
+        Object result;
+        Var v0 = new Var(3115);
+        script = jexl.createScript("(x)->{ x.value}");
+        result = script.execute(jc, v0);
+        Assert.assertEquals(3115, result);
+        script = jexl.createScript("(x)->{ x['VALUE']}");
+        result = script.execute(jc, v0);
+        Assert.assertEquals(3115, result);
+        script = jexl.createScript("(x,y)->{ x.value = y}");
+        result = script.execute(jc, v0, 42);
+        Assert.assertEquals(42, result);
+        script = jexl.createScript("(x,y)->{ x['VALUE'] = y}");
+        result = script.execute(jc, v0, 169);
+        Assert.assertEquals(169, result);
+    }
+
     public static class Var {
         int value;
 
@@ -349,6 +372,22 @@ public class SideEffectTest extends Jexl
             super(strict);
         }
 
+        public Object propertyGet(Var var, String property) {
+            return "value".equals(property)? var.value : JexlEngine.TRY_FAILED;
+        }
+
+        public Object propertySet(Var var, String property, int v) {
+            return "value".equals(property)? var.value = v : JexlEngine.TRY_FAILED;
+        }
+
+        public Object arrayGet(Var var, String property) {
+            return "VALUE".equals(property)? var.value : JexlEngine.TRY_FAILED;
+        }
+
+        public Object arraySet(Var var, String property, int v) {
+            return "VALUE".equals(property)? var.value = v : JexlEngine.TRY_FAILED;
+        }
+
         public JexlOperator selfAdd(Var lhs, Var rhs) {
             lhs.value += rhs.value;
             return JexlOperator.ASSIGN;

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java?rev=1698224&r1=1698223&r2=1698224&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/StrategyTest.java Thu Aug 27 20:06:53 2015
@@ -17,7 +17,6 @@
 package org.apache.commons.jexl3;
 
 import org.apache.commons.jexl3.internal.Engine;
-import org.apache.commons.jexl3.introspection.JexlUberspect;
 import java.util.HashMap;
 import java.util.Map;
 import org.junit.Assert;
@@ -34,6 +33,29 @@ public class StrategyTest extends JexlTe
         super("StrategyTest");
     }
 
+    // JEXL-174
+    public static class MapArithmetic extends JexlArithmetic {
+        public MapArithmetic(boolean flag) {
+            super(flag);
+        }
+
+        public Object propertyGet(Map<?,?> map, Object identifier) {
+            return arrayGet(map, identifier);
+        }
+
+        public Object propertySet(Map<Object, Object> map, Object identifier, Object value) {
+             return arraySet(map, identifier, value);
+        }
+
+        public Object arrayGet(Map<?,?> map, Object identifier) {
+            return map.get(identifier);
+        }
+
+        public Object arraySet(Map<Object, Object> map, Object identifier, Object value) {
+             map.put(identifier, value);
+             return value;
+        }
+    }
 
     @Test
     public void testJexlStrategy() throws Exception {
@@ -43,7 +65,7 @@ public class StrategyTest extends JexlTe
 
     @Test
     public void testMapStrategy() throws Exception {
-        final JexlEngine jexl = new JexlBuilder().strategy(JexlUberspect.MAP_STRATEGY).create();
+        final JexlEngine jexl = new JexlBuilder().arithmetic( new MapArithmetic(true)).create();
         run171(jexl, false);
     }