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:10:40 UTC

svn commit: r1698225 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/ main/java/org/apache/commons/jexl3/internal/introspection/ main/java/org/apache/commons/jexl3/introspection/ site/xdoc/ site/xdoc/reference/ test/java/org/apa...

Author: henrib
Date: Thu Aug 27 20:10:39 2015
New Revision: 1698225

URL: http://svn.apache.org/r1698225
Log:
JEXL:
Fix for tryInvoke that could fail on some cases (overload + cache + switching argument types);
Other modifications and tests for JEXL-17{1,3,4,7,8};
Update to doc (package.html,syntax.xml,changes.xml)

Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckGetExecutor.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckSetExecutor.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertyGetExecutor.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html
    commons/proper/jexl/trunk/src/site/xdoc/changes.xml
    commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/introspection/DiscoveryTest.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckGetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckGetExecutor.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckGetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckGetExecutor.java Thu Aug 27 20:10:39 2015
@@ -80,6 +80,8 @@ public final class DuckGetExecutor exten
                 return TRY_FAILED; // fail
             } catch (IllegalAccessException xill) {
                 return TRY_FAILED;// fail
+            } catch (IllegalArgumentException xarg) {
+                return TRY_FAILED;// fail
             }
         }
         return TRY_FAILED;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckSetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckSetExecutor.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckSetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/DuckSetExecutor.java Thu Aug 27 20:10:39 2015
@@ -95,6 +95,8 @@ public final class DuckSetExecutor exten
                 return TRY_FAILED; // fail
             } catch (IllegalAccessException xill) {
                 return TRY_FAILED;// fail
+            } catch (IllegalArgumentException xarg) {
+                return TRY_FAILED;// fail
             }
         }
         return TRY_FAILED;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodExecutor.java Thu Aug 27 20:10:39 2015
@@ -103,9 +103,11 @@ public final class MethodExecutor extend
             try {
                 return invoke(obj, args);
             } catch (InvocationTargetException xinvoke) {
-                return JexlEngine.TRY_FAILED; // fail
+                return TRY_FAILED; // fail
             } catch (IllegalAccessException xill) {
-                return JexlEngine.TRY_FAILED;// fail
+                return TRY_FAILED;// fail
+            } catch (IllegalArgumentException xarg) {
+                return TRY_FAILED;// fail
             }
         }
         return JexlEngine.TRY_FAILED;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertyGetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertyGetExecutor.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertyGetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertyGetExecutor.java Thu Aug 27 20:10:39 2015
@@ -75,6 +75,8 @@ public final class PropertyGetExecutor e
                 return TRY_FAILED; // fail
             } catch (IllegalAccessException xill) {
                 return TRY_FAILED;// fail
+            } catch (IllegalArgumentException xarg) {
+                return TRY_FAILED;// fail
             }
         }
         return TRY_FAILED;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/PropertySetExecutor.java Thu Aug 27 20:10:39 2015
@@ -93,13 +93,15 @@ public class PropertySetExecutor extends
                 return TRY_FAILED; // fail
             } catch (IllegalAccessException xill) {
                 return TRY_FAILED;// fail
+            } catch (IllegalArgumentException xarg) {
+                return TRY_FAILED;// fail
             }
         }
         return TRY_FAILED;
     }
 
     /**
-     * Checks wether an argument is an empty array.
+     * Checks whether an argument is an empty array.
      * @param arg the argument
      * @return true if <code>arg</code> is an empty array
      */

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/SandboxUberspect.java Thu Aug 27 20:10:39 2015
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl3.internal.introspection;
 
 import org.apache.commons.jexl3.JexlArithmetic;
+import org.apache.commons.jexl3.JexlOperator;
 import org.apache.commons.jexl3.introspection.JexlMethod;
 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
 import org.apache.commons.jexl3.introspection.JexlPropertySet;
@@ -41,7 +42,7 @@ public final class SandboxUberspect impl
      * @param theUberspect the JexlUberspect to sandbox
      * @param theSandbox the sandbox which is copied to avoid changes at runtime
      */
-    public SandboxUberspect(JexlUberspect theUberspect, JexlSandbox theSandbox) {
+    public SandboxUberspect(final JexlUberspect theUberspect, final JexlSandbox theSandbox) {
         if (theSandbox == null) {
             throw new NullPointerException("sandbox can not be null");
         }
@@ -72,7 +73,7 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlMethod getConstructor(Object ctorHandle, Object... args) {
+    public JexlMethod getConstructor(final Object ctorHandle, final Object... args) {
         final String className;
         if (ctorHandle instanceof Class<?>) {
             Class<?> clazz = (Class<?>) ctorHandle;
@@ -92,7 +93,7 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlMethod getMethod(Object obj, String method, Object... args) {
+    public JexlMethod getMethod(final Object obj, final String method, final Object... args) {
         if (obj != null && method != null) {
             String objClassName = (obj instanceof Class) ? ((Class<?>)obj).getName() : obj.getClass().getName();
             String actual = sandbox.execute(objClassName, method);
@@ -107,7 +108,15 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlPropertyGet getPropertyGet(Object obj, Object identifier) {
+    public List<PropertyResolver> getResolvers(JexlOperator op, Object obj) {
+        return uberspect.getResolvers(op, obj);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public JexlPropertyGet getPropertyGet(final Object obj, final Object identifier) {
         return getPropertyGet(null, obj, identifier);
     }
 
@@ -115,11 +124,13 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlPropertyGet getPropertyGet(List<ResolverType> strategy, Object obj, Object identifier) {
+    public JexlPropertyGet getPropertyGet(final List<PropertyResolver> resolvers,
+                                          final Object obj,
+                                          final Object identifier) {
         if (obj != null && identifier != null) {
             String actual = sandbox.read(obj.getClass().getName(), identifier.toString());
             if (actual != null) {
-                return uberspect.getPropertyGet(strategy, obj, actual);
+                return uberspect.getPropertyGet(resolvers, obj, actual);
             }
         }
         return null;
@@ -129,7 +140,7 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlPropertySet getPropertySet(final Object obj, final Object identifier, Object arg) {
+    public JexlPropertySet getPropertySet(final Object obj,final Object identifier,final Object arg) {
         return getPropertySet(null, obj, identifier, arg);
     }
 
@@ -137,22 +148,24 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlPropertySet getPropertySet(final List<ResolverType> strategy, final Object obj, final Object identifier, Object arg) {
+    public JexlPropertySet getPropertySet(final List<PropertyResolver> resolvers,
+                                          final Object obj,
+                                          final Object identifier,
+                                          final Object arg) {
         if (obj != null && identifier != null) {
             String actual = sandbox.write(obj.getClass().getName(), identifier.toString());
             if (actual != null) {
-                return uberspect.getPropertySet(strategy, obj, actual, arg);
+                return uberspect.getPropertySet(resolvers, obj, actual, arg);
             }
         }
         return null;
-
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public Iterator<?> getIterator(Object obj) {
+    public Iterator<?> getIterator(final Object obj) {
         return uberspect.getIterator(obj);
     }
 
@@ -160,7 +173,7 @@ public final class SandboxUberspect impl
      * {@inheritDoc}
      */
     @Override
-    public JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic) {
+    public JexlArithmetic.Uberspect getArithmetic(final JexlArithmetic arithmetic) {
         return uberspect.getArithmetic(arithmetic);
     }
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java Thu Aug 27 20:10:39 2015
@@ -50,9 +50,7 @@ import java.util.List;
  * @since 1.0
  */
 public class Uberspect implements JexlUberspect {
-    /**
-     * Publicly exposed special failure object returned by tryInvoke.
-     */
+    /** Publicly exposed special failure object returned by tryInvoke. */
     public static final Object TRY_FAILED = JexlEngine.TRY_FAILED;
     /** The logger to use for all warnings and errors. */
     protected final Logger rlog;
@@ -62,7 +60,7 @@ public class Uberspect implements JexlUb
     private final AtomicInteger version;
     /** The soft reference to the introspector currently in use. */
     private volatile Reference<Introspector> ref;
-    /** The class loader reference; used to recreate the Introspector when necessary. */
+    /** The class loader reference; used to recreate the introspector when necessary. */
     private volatile Reference<ClassLoader> loader;
     /**
      * The map from arithmetic classes to overloaded operator sets.
@@ -111,6 +109,9 @@ public class Uberspect implements JexlUb
     }
     // CSON: DoubleCheckedLocking
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public void setClassLoader(ClassLoader nloader) {
         synchronized (this) {
@@ -127,6 +128,9 @@ public class Uberspect implements JexlUb
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int getVersion() {
         return version.intValue();
@@ -215,69 +219,84 @@ public class Uberspect implements JexlUb
         return base().getMethods(c, methodName);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlMethod getMethod(Object obj, String method, Object... args) {
         return MethodExecutor.discover(base(), obj, method, args);
     }
 
-//    @Override
-//    public List<ResolverType> getStrategy(List<ResolverType> resolvers, Object obj) {
-//        return strategy.apply(resolvers, obj);
-//    }
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<PropertyResolver> getResolvers(JexlOperator op, Object obj) {
+        return strategy.apply(op, obj);
+    }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlPropertyGet getPropertyGet(Object obj, Object identifier) {
         return getPropertyGet(null, obj, identifier);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlPropertyGet getPropertyGet(
-            final List<ResolverType> resolvers, final Object obj, final Object identifier
+            final List<PropertyResolver> resolvers, final Object obj, final Object identifier
     ) {
-
-        final List<ResolverType> actual = strategy.apply(resolvers, obj);
         final Class<?> claz = obj.getClass();
         final String property = AbstractExecutor.castString(identifier);
         final Introspector is = base();
+        final List<PropertyResolver> r = resolvers == null? strategy.apply(null, obj) : resolvers;
         JexlPropertyGet executor = null;
-        for (ResolverType resolver : actual) {
-            switch (resolver) {
-                case PROPERTY:
-                    // first try for a getFoo() type of property (also getfoo() )
-                    executor = PropertyGetExecutor.discover(is, claz, property);
-                    if (executor == null) {
-                        executor = BooleanGetExecutor.discover(is, claz, property);
-                    }
-                    break;
-                case MAP:
-                    // let's see if we are a map...
-                    executor = MapGetExecutor.discover(is, claz, identifier);
-                    break;
-                case LIST:
-                    // let's see if this is a list or array
-                    Integer index = AbstractExecutor.castInteger(identifier);
-                    if (index != null) {
-                        executor = ListGetExecutor.discover(is, claz, index);
-                    }
-                    break;
-                case DUCK:
-                    // if that didn't work, look for get(foo)
-                    executor = DuckGetExecutor.discover(is, claz, identifier);
-                    if (executor == null && property != null && property != identifier) {
-                        // look for get("foo") if we did not try yet (just above)
-                        executor = DuckGetExecutor.discover(is, claz, property);
-                    }
-                    break;
-                case FIELD:
-                    // a field may be? (can not be a number)
-                    executor = FieldGetExecutor.discover(is, claz, property);
-                    break;
-                case CONTAINER:
-                    // or an indexed property?
-                    executor = IndexedType.discover(is, obj, property);
-                    break;
-                default:
-                    continue; // in case we add new ones in enum
+        for (PropertyResolver resolver : r) {
+            if (resolver instanceof JexlResolver) {
+                switch ((JexlResolver) resolver) {
+                    case PROPERTY:
+                        // first try for a getFoo() type of property (also getfoo() )
+                        executor = PropertyGetExecutor.discover(is, claz, property);
+                        if (executor == null) {
+                            executor = BooleanGetExecutor.discover(is, claz, property);
+                        }
+                        break;
+                    case MAP:
+                        // let's see if we are a map...
+                        executor = MapGetExecutor.discover(is, claz, identifier);
+                        break;
+                    case LIST:
+                        // let's see if this is a list or array
+                        Integer index = AbstractExecutor.castInteger(identifier);
+                        if (index != null) {
+                            executor = ListGetExecutor.discover(is, claz, index);
+                        }
+                        break;
+                    case DUCK:
+                        // if that didn't work, look for get(foo)
+                        executor = DuckGetExecutor.discover(is, claz, identifier);
+                        if (executor == null && property != null && property != identifier) {
+                            // look for get("foo") if we did not try yet (just above)
+                            executor = DuckGetExecutor.discover(is, claz, property);
+                        }
+                        break;
+                    case FIELD:
+                        // a field may be? (can not be a number)
+                        executor = FieldGetExecutor.discover(is, claz, property);
+                        break;
+                    case CONTAINER:
+                        // or an indexed property?
+                        executor = IndexedType.discover(is, obj, property);
+                        break;
+                    default:
+                        continue; // in case we add new ones in enum
+                }
+            } else {
+                executor = resolver.getPropertyGet(this, obj, identifier);
             }
             if (executor != null) {
                 return executor;
@@ -285,53 +304,62 @@ public class Uberspect implements JexlUb
         }
         return null;
     }
-
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlPropertySet getPropertySet(final Object obj, final Object identifier, final Object arg) {
         return getPropertySet(null, obj, identifier, arg);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlPropertySet getPropertySet(
-           final List<ResolverType> resolvers, final Object obj, final Object identifier, final Object arg
+            final List<PropertyResolver> resolvers, final Object obj, final Object identifier, final Object arg
     ) {
-        final List<ResolverType> actual = strategy.apply(resolvers, obj);
         final Class<?> claz = obj.getClass();
         final String property = AbstractExecutor.castString(identifier);
         final Introspector is = base();
+        final List<PropertyResolver> actual = resolvers == null? strategy.apply(null, obj) : resolvers;
         JexlPropertySet executor = null;
-        for (ResolverType resolver : actual) {
-            switch (resolver) {
-                case PROPERTY:
-                    // first try for a setFoo() type of property (also setfoo() )
-                    executor = PropertySetExecutor.discover(is, claz, property, arg);
-                    break;
-                case MAP:
-                    // let's see if we are a map...
-                    executor = MapSetExecutor.discover(is, claz, identifier, arg);
-                    break;
-                case LIST:
+        for (PropertyResolver resolver : actual) {
+            if (resolver instanceof JexlResolver) {
+                switch ((JexlResolver) resolver) {
+                    case PROPERTY:
+                        // first try for a setFoo() type of property (also setfoo() )
+                        executor = PropertySetExecutor.discover(is, claz, property, arg);
+                        break;
+                    case MAP:
+                        // let's see if we are a map...
+                        executor = MapSetExecutor.discover(is, claz, identifier, arg);
+                        break;
+                    case LIST:
                     // let's see if we can convert the identifier to an int,
-                    // if obj is an array or a list, we can still do something
-                    Integer index = AbstractExecutor.castInteger(identifier);
-                    if (index != null) {
-                        executor = ListSetExecutor.discover(is, claz, identifier, arg);
-                    }
-                    break;
-                case DUCK:
-                    // if that didn't work, look for set(foo)
-                    executor = DuckSetExecutor.discover(is, claz, identifier, arg);
-                    if (executor == null && property != null && property != identifier) {
-                        executor = DuckSetExecutor.discover(is, claz, property, arg);
-                    }
-                    break;
-                case FIELD:
-                    // a field may be?
-                    executor = FieldSetExecutor.discover(is, claz, property, arg);
-                    break;
-                case CONTAINER:
-                default:
-                    continue; // in case we add new ones in enum
+                        // if obj is an array or a list, we can still do something
+                        Integer index = AbstractExecutor.castInteger(identifier);
+                        if (index != null) {
+                            executor = ListSetExecutor.discover(is, claz, identifier, arg);
+                        }
+                        break;
+                    case DUCK:
+                        // if that didn't work, look for set(foo)
+                        executor = DuckSetExecutor.discover(is, claz, identifier, arg);
+                        if (executor == null && property != null && property != identifier) {
+                            executor = DuckSetExecutor.discover(is, claz, property, arg);
+                        }
+                        break;
+                    case FIELD:
+                        // a field may be?
+                        executor = FieldSetExecutor.discover(is, claz, property, arg);
+                        break;
+                    case CONTAINER:
+                    default:
+                        continue; // in case we add new ones in enum
+                }
+            } else {
+                executor = resolver.getPropertySet(this, obj, identifier, arg);
             }
             if (executor != null) {
                 return executor;
@@ -340,6 +368,9 @@ public class Uberspect implements JexlUb
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     @SuppressWarnings("unchecked")
     public Iterator<?> getIterator(Object obj) {
@@ -374,6 +405,9 @@ public class Uberspect implements JexlUb
         return null;
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlMethod getConstructor(Object ctorHandle, Object... args) {
         return ConstructorMethod.discover(base(), ctorHandle, args);
@@ -401,16 +435,9 @@ public class Uberspect implements JexlUb
         }
 
         @Override
-        public JexlMethod getOperator(JexlOperator operator, Object arg) {
-            return overloads.contains(operator) && arg != null
-                   ? getMethod(arithmetic, operator.getMethodName(), arg)
-                   : null;
-        }
-
-        @Override
-        public JexlMethod getOperator(JexlOperator operator, Object lhs, Object rhs) {
-            return overloads.contains(operator) && lhs != null && rhs != null
-                   ? getMethod(arithmetic, operator.getMethodName(), lhs, rhs)
+        public JexlMethod getOperator(JexlOperator operator, Object... args) {
+            return overloads.contains(operator) && args != null
+                   ? getMethod(arithmetic, operator.getMethodName(), args)
                    : null;
         }
 
@@ -420,6 +447,9 @@ public class Uberspect implements JexlUb
         }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic) {
         JexlArithmetic.Uberspect jau = null;

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlUberspect.java Thu Aug 27 20:10:39 2015
@@ -14,10 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.jexl3.introspection;
 
 import org.apache.commons.jexl3.JexlArithmetic;
+import org.apache.commons.jexl3.JexlOperator;
+
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
@@ -26,26 +27,51 @@ import java.util.Map;
 
 /**
  * 'Federated' introspection/reflection interface to allow JEXL introspection
- *  behavior to be customized.
+ * behavior to be customized.
  *
  * @since 1.0
  */
 public interface JexlUberspect {
     /**
-     * The various property resolver types.
-     * <p>
-     * Each resolver type discovers how to set/get a property with different techniques; seeking
-     * method names or field names, etc.
+     * Abstracts getting property setter and getter.
      * <p>
      * These are used through 'strategies' to solve properties; a strategy orders a list of resolver types,
      * and each resolver type is tried in sequence; the first resolver that discovers a non null {s,g}etter
      * stops the search.
-     * @see ResolverStrategy
+     * @see JexlResolver
      * @see JexlUberspect#getPropertyGet
      * @see JexlUberspect#getPropertySet
      * @since 3.0
      */
-    enum ResolverType {
+    interface PropertyResolver {
+        /**
+         * Gets a property getter.
+         * @param uber       the uberspect
+         * @param obj        the object
+         * @param identifier the property identifier
+         * @return the property getter or null
+         */
+        JexlPropertyGet getPropertyGet(JexlUberspect uber, Object obj, Object identifier);
+
+        /**
+         * Gets a property setter.
+         * @param uber       the uberspect
+         * @param obj        the object
+         * @param identifier the property identifier
+         * @param arg        the property value
+         * @return the property setter or null
+         */
+        JexlPropertySet getPropertySet(JexlUberspect uber, Object obj, Object identifier, Object arg);
+    }
+
+    /**
+     * The various builtin property resolvers.
+     * <p>
+     * Each resolver discovers how to set/get a property with different techniques; seeking
+     * method names or field names, etc.
+     * @since 3.0
+     */
+    enum JexlResolver implements PropertyResolver {
         /**
          * Seeks methods named get{P,p}property and is{P,p}property.
          */
@@ -70,90 +96,119 @@ public interface JexlUberspect {
          * Seeks a getContainer(property) and setContainer(property, value)
          * as in <code>x.container.property</code>.
          */
-        CONTAINER
+        CONTAINER;
+
+        @Override
+        public final JexlPropertyGet getPropertyGet(JexlUberspect uber, Object obj, Object identifier) {
+            return uber.getPropertyGet(Collections.<PropertyResolver>singletonList(this), obj, identifier);
+        }
+
+        @Override
+        public final JexlPropertySet getPropertySet(JexlUberspect uber, Object obj, Object identifier, Object arg) {
+            return uber.getPropertySet(Collections.<PropertyResolver>singletonList(this), obj, identifier);
+        }
     }
 
     /**
      * A resolver types list tailored for POJOs, favors '.' over '[]'.
      */
-    List<ResolverType> POJO = Collections.unmodifiableList(Arrays.asList(
-        ResolverType.PROPERTY,
-        ResolverType.MAP,
-        ResolverType.LIST,
-        ResolverType.DUCK,
-        ResolverType.FIELD,
-        ResolverType.CONTAINER
+    List<PropertyResolver> POJO = Collections.<PropertyResolver>unmodifiableList(Arrays.asList(
+            JexlResolver.PROPERTY,
+            JexlResolver.MAP,
+            JexlResolver.LIST,
+            JexlResolver.DUCK,
+            JexlResolver.FIELD,
+            JexlResolver.CONTAINER
     ));
 
     /**
      * A resolver types list tailored for Maps, favors '[]' over '.'.
      */
-    List<ResolverType> MAP = Collections.unmodifiableList(Arrays.asList(
-        ResolverType.MAP,
-        ResolverType.LIST,
-        ResolverType.DUCK,
-        ResolverType.PROPERTY,
-        ResolverType.FIELD,
-        ResolverType.CONTAINER
-     ));
+    List<PropertyResolver> MAP = Collections.<PropertyResolver>unmodifiableList(Arrays.asList(
+            JexlResolver.MAP,
+            JexlResolver.LIST,
+            JexlResolver.DUCK,
+            JexlResolver.PROPERTY,
+            JexlResolver.FIELD,
+            JexlResolver.CONTAINER
+    ));
 
     /**
-     * Determine property resolution strategies.
+     * Determines property resolution strategy.
      * <p>
      * To use a strategy instance, you have to set it at engine creation using
      * {@link org.apache.commons.jexl3.JexlBuilder#strategy(JexlUberspect.ResolverStrategy)}
      * as in:<br/>
      * <code>JexlEngine jexl = new JexlBuilder().strategy(MY_STRATEGY).create();</code>
-     * @see ResolverType
      * @since 3.0
      */
     interface ResolverStrategy {
         /**
          * Applies this strategy to a list of resolver types.
          * <p>
-         * <ul>In the default implementation, the resolvers argument depends on the calling situation:
-         * <li>{@link #POJO} for dot operator resolution (foo.bar )</li>
-         * <li>{@link #MAP} for bracket operator resolution (foo['bar'])</li>
-         * <li>null when called from {@link #getPropertyGet(java.lang.Object, java.lang.Object) }
-         * or {@link #getPropertySet(java.lang.Object, java.lang.Object, java.lang.Object)}</li>
-         * </ul>
-         *
-         * @param resolvers candidate resolver types list
-         * @param obj the instance we seek to obtain a property setter/getter from, can not be null
+         * @param operator the property access operator, may be null
+         * @param obj      the instance we seek to obtain a property setter/getter from, can not be null
          * @return the ordered list of resolvers types, must not be null
          */
-        List<ResolverType> apply(List<ResolverType> resolvers, Object obj);
+        List<PropertyResolver> apply(JexlOperator operator, Object obj);
     }
 
     /**
      * The default strategy.
      * <p>
-     * If the resolvers list is not null, use that list.
-     * Otherwise, if the object is a map, use the MAP list, otherwise use the POJO list.
+     * If the operator is '[]' or if the operator is null and the object is a map, use the MAP list of resolvers;
+     * Other cases use the POJO list of resolvers.
      */
     ResolverStrategy JEXL_STRATEGY = new ResolverStrategy() {
         @Override
-        public List<ResolverType> apply(List<ResolverType> resolvers, Object obj) {
-            return resolvers != null ? resolvers : obj instanceof Map? JexlUberspect.MAP : JexlUberspect.POJO;
+        public List<PropertyResolver> apply(JexlOperator op, Object obj) {
+            if (op == JexlOperator.ARRAY_GET) {
+                return MAP;
+            }
+            if (op == JexlOperator.ARRAY_SET) {
+                return MAP;
+            }
+            if (op == null && obj instanceof Map) {
+                return MAP;
+            }
+            return POJO;
         }
     };
 
     /**
      * The map strategy.
      * <p>
-     * If the object is a map, use the MAP list.
-     * Otherwise, if the resolvers list is not null, use that list, otherwise use the POJO list.
+     * If the operator is '[]' or if the object is a map, use the MAP list of resolvers.
+     * Otherwise, use the POJO list of resolvers.
      */
     ResolverStrategy MAP_STRATEGY = new ResolverStrategy() {
         @Override
-        public List<ResolverType> apply(List<ResolverType> strategy, Object obj) {
-            return obj instanceof Map? JexlUberspect.MAP : strategy != null ? strategy : JexlUberspect.POJO;
+        public List<PropertyResolver> apply(JexlOperator op, Object obj) {
+            if (op == JexlOperator.ARRAY_GET) {
+                return MAP;
+            }
+            if (op == JexlOperator.ARRAY_SET) {
+                return MAP;
+            }
+            if (obj instanceof Map) {
+                return MAP;
+            }
+            return POJO;
         }
     };
 
     /**
+     * Applies this uberspect property resolver strategy.
+     * @param op the operator
+     * @param obj the object
+     * @return the applied strategy resolver list
+     */
+    List<PropertyResolver> getResolvers(JexlOperator op, Object obj);
+
+    /**
      * Sets the class loader to use.
-     * <p>This increments the version.</p>
+     * <p>
+     * This increments the version.</p>
      * @param loader the class loader
      */
     void setClassLoader(ClassLoader loader);
@@ -167,7 +222,7 @@ public interface JexlUberspect {
     /**
      * Returns a class constructor.
      * @param ctorHandle a class or class name
-     * @param args constructor arguments
+     * @param args       constructor arguments
      * @return a {@link JexlMethod}
      * @since 3.0
      */
@@ -175,17 +230,18 @@ public interface JexlUberspect {
 
     /**
      * Returns a JexlMethod.
-     * @param obj the object
+     * @param obj    the object
      * @param method the method name
-     * @param args method arguments
+     * @param args   method arguments
      * @return a {@link JexlMethod}
      */
     JexlMethod getMethod(Object obj, String method, Object... args);
 
     /**
      * Property getter.
-     * <p>returns a JelPropertySet apropos to an expression like <code>bar.woogie</code>.</p>
-     * @param obj the object to get the property from
+     * <p>
+     * returns a JelPropertySet apropos to an expression like <code>bar.woogie</code>.</p>
+     * @param obj        the object to get the property from
      * @param identifier property name
      * @return a {@link JexlPropertyGet} or null
      */
@@ -193,40 +249,43 @@ public interface JexlUberspect {
 
     /**
      * Property getter.
-     * <p>Seeks a JexlPropertyGet apropos to an expression like <code>bar.woogie</code>.</p>
-     * @param resolvers  the list of resolver types,
-     *                   argument to {@link ResolverStrategy#apply(java.util.List, java.lang.Object) }
-     * @param obj        the object to get the property from,
-     *                   argument to {@link ResolverStrategy#apply(java.util.List, java.lang.Object) }
+     * <p>
+     * Seeks a JexlPropertyGet apropos to an expression like <code>bar.woogie</code>.</p>
+     * See {@link ResolverStrategy#apply(JexlOperator, java.lang.Object) }
+     *
+     * @param resolvers  the list of property resolvers to try
+     * @param obj        the object to get the property from
      * @param identifier property name
      * @return a {@link JexlPropertyGet} or null
      * @since 3.0
      */
-    JexlPropertyGet getPropertyGet(List<ResolverType> resolvers, Object obj, Object identifier);
+    JexlPropertyGet getPropertyGet(List<PropertyResolver> resolvers, Object obj, Object identifier);
 
     /**
      * Property setter.
-     * <p>Seeks a JelPropertySet apropos to an expression like  <code>foo.bar = "geir"</code>.</p>
-     * @param obj the object to get the property from.
+     * <p>
+     * Seeks a JelPropertySet apropos to an expression like  <code>foo.bar = "geir"</code>.</p>
+     * @param obj        the object to get the property from.
      * @param identifier property name
-     * @param arg value to set
+     * @param arg        value to set
      * @return a {@link JexlPropertySet} or null
      */
     JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg);
 
     /**
      * Property setter.
-     * <p>Seeks a JelPropertySet apropos to an expression like <code>foo.bar = "geir"</code>.</p>
-     * @param resolvers  the list of resolver types,
-     *                   argument to {@link ResolverStrategy#apply(java.util.List, java.lang.Object) }
-     * @param obj        the object to get the property from,
-     *                   argument to {@link ResolverStrategy#apply(java.util.List, java.lang.Object) }
+     * <p>
+     * Seeks a JelPropertySet apropos to an expression like <code>foo.bar = "geir"</code>.</p>
+     * See {@link ResolverStrategy#apply(JexlOperator, java.lang.Object) }
+     *
+     * @param resolvers  the list of property resolvers to try,
+     * @param obj        the object to get the property from
      * @param identifier property name
      * @param arg        value to set
      * @return a {@link JexlPropertySet} or null
      * @since 3.0
      */
-    JexlPropertySet getPropertySet(List<ResolverType> resolvers, Object obj, Object identifier, Object arg);
+    JexlPropertySet getPropertySet(List<PropertyResolver> resolvers, Object obj, Object identifier, Object arg);
 
     /**
      * Gets an iterator from an object.
@@ -243,4 +302,4 @@ public interface JexlUberspect {
      */
     JexlArithmetic.Uberspect getArithmetic(JexlArithmetic arithmetic);
 
-}
\ No newline at end of file
+}

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/package.html Thu Aug 27 20:10:39 2015
@@ -71,7 +71,7 @@
         <ul>
             <li>Dynamic invocation of setters, getters, methods and constructors</li>
             <li>Script expressions known as JEXL expressions</li>
-            <li>JSP/JSF like expression known as UnifiedJEXL expressions</li>
+            <li>JSP/JSF like expression known as JXLT expressions</li>
         </ul>
 
         <h3><a name="usage_note">Important note</a></h3>
@@ -197,9 +197,13 @@
             everything after the first semi-colon and just returns the result from
             the first command.
         </p>
+        <p>
+            Also note that expressions are not statements (which is what scripts are made of) and do not allow
+            using the flow control (if, while, for), variables or lambdas syntactic elements.
+        </p>
         <h4>JexlScript</h4>
         <p>
-            This allows you to put multiple commands in the expression and you can
+            These allow you to use multiple statements and you can
             use variable assignments, loops, calculations, etc. More or less what can be achieved in Shell or
             JavaScript at its basic level. The result from the last command is returned from the script.
         </p>
@@ -311,7 +315,7 @@
 
         <h3><a name="dynamic_configuration">Dynamic Configuration</a></h3>
         <p>
-            Those configuration options can be overriden during evaluation by implementing a
+            Those configuration options can be overridden during evaluation by implementing a
             {@link org.apache.commons.jexl3.JexlContext}
             that also implements {@link org.apache.commons.jexl3.JexlEngine$Options} to carry evaluation options.
             An example of such a class exists in the test package.
@@ -464,8 +468,40 @@
                 </tr>
             </table>
         <p>
-            You can also override the base operator methods, those whose arguments are Object.
+            You can also add methods to overload property getters and setters operators behaviors.
+            Public methods of the JexlArithmetic instance named propertyGet/propertySet/arrayGet/arraySet are potential
+            overrides that will be called when appropriate.
+            The following table is an overview of the relation between a syntactic form and the method to call
+            where V is the property value class, O the object class and  P the property identifier class (usually String or Integer).
+        </p>
+
+            <table>
+                <tr>
+                    <th>Expression</th>
+                    <th>Method Template</th>
+                </tr>
+                <tr>
+                    <td>foo.property</td>
+                    <td>public V propertyGet(O obj, P property);</td>
+                </tr>
+                <tr>
+                    <td>foo.property = value</td>
+                    <td>public V propertySet(O obj, P property, V value);</td>
+                </tr>
+                <tr>
+                    <td>foo[property]</td>
+                    <td>public V arrayGet(O obj, P property, V value);</td>
+                </tr>
+                <tr>
+                    <td>foo[property] = value</td>
+                    <td>public V arraySet(O obj, P property, V value);</td>
+                </tr>
+            </table>
+        <p>
+            You can also override the base operator methods, those whose arguments are Object which gives you total
+            control.
         </p>
+
         <h2><a name="extension">Extending JEXL</a></h2>
         If you need to make JEXL treat some objects in a specialized manner or tweak how it
         reacts to some settings, you can derive most of its inner-workings. The classes and methods are rarely private or

Modified: commons/proper/jexl/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/changes.xml?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Thu Aug 27 20:10:39 2015
@@ -26,6 +26,18 @@
     </properties>
     <body>
         <release version="3.0" date="unreleased">
+            <action dev="henrib" type="add" issue="JEXL-178 " due-to="Dmitri Blinov">
+                'Unsolvable property' message to provide details about underlying exception
+            </action>
+            <action dev="henrib" type="add" issue="JEXL-177" due-to="Dmitri Blinov">
+            Unified expressions to be used in String literals in Jexl scripts
+            </action>
+            <action dev="henrib" type="add" issue="JEXL-174" due-to="Dmitri Blinov">
+                Overloadable property access operators
+            </action>
+            <action dev="henrib" type="add" issue="JEXL-173" due-to="Dmitri Blinov">
+                Duck-typed java closures
+            </action>
             <action dev="henrib" type="fix" issue="JEXL-171" due-to="Dmitri Blinov">
                 Map access operator does not work if key name clashes with map property name
             </action>

Modified: commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/reference/syntax.xml Thu Aug 27 20:10:39 2015
@@ -235,6 +235,16 @@
           </td>
         </tr>
         <tr>
+            <td>Multiline format literals</td>
+            <td>
+                Start and end with <code>`</code> delimiter - back-quote -, e.g. <source>`Hello world`</source>
+                <p>The escape character is <code>\</code> (backslash); it only escapes the string delimiter.</p>
+                These format literals can span multiple lines and allow Unified JEXL expressions (JSTL like expressions)
+                to be interpolated. If a variable <code>user</code> valued <code>JEXL</code>is present in the environment - whether
+                as a local or global variable -, the format <source>`Hello ${user}`</source> will evaluate as <source>Hello JEXL</source>.
+            </td>
+        </tr>
+        <tr>
           <td>Boolean literals</td>
           <td>
             The literals <code>true</code> and <code>false</code> can be used, e.g.

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/introspection/DiscoveryTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/introspection/DiscoveryTest.java?rev=1698225&r1=1698224&r2=1698225&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/introspection/DiscoveryTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/internal/introspection/DiscoveryTest.java Thu Aug 27 20:10:39 2015
@@ -104,7 +104,7 @@ public class DiscoveryTest extends JexlT
 
     @Test
     public void testBeanIntrospection() throws Exception {
-        Uberspect uber = Engine.getUberspect(null,null);
+        Uberspect uber = Engine.getUberspect(null, null);
         Bean bean = new Bean("JEXL", "LXEJ");
 
         JexlPropertyGet get = uber.getPropertyGet(bean, "value");
@@ -133,7 +133,7 @@ public class DiscoveryTest extends JexlT
 
     @Test
     public void testDuckIntrospection() throws Exception {
-        Uberspect uber = Engine.getUberspect(null,null);
+        Uberspect uber = Engine.getUberspect(null, null);
         Duck duck = new Duck("JEXL", "LXEJ");
 
         JexlPropertyGet get = uber.getPropertyGet(duck, "value");
@@ -161,7 +161,7 @@ public class DiscoveryTest extends JexlT
 
     @Test
     public void testListIntrospection() throws Exception {
-        Uberspect uber = Engine.getUberspect(null,null);
+        Uberspect uber = Engine.getUberspect(null, null);
         List<Object> list = new ArrayList<Object>();
         list.add("LIST");
         list.add("TSIL");
@@ -192,7 +192,7 @@ public class DiscoveryTest extends JexlT
 
     @Test
     public void testMapIntrospection() throws Exception {
-        Uberspect uber = Engine.getUberspect(null,null);
+        Uberspect uber = Engine.getUberspect(null, null);
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("value", "MAP");
         map.put("eulav", "PAM");