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 2013/11/25 14:35:57 UTC

svn commit: r1545274 [2/3] - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/ main/java/org/apache/commons/jexl3/internal/ main/java/org/apache/commons/jexl3/internal/introspection/ main/java/org/apache/commons/jexl3/introspection...

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListGetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListGetExecutor.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListGetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListGetExecutor.java Mon Nov 25 13:35:55 2013
@@ -35,34 +35,33 @@ public final class ListGetExecutor exten
 
     /**
      * Attempts to discover a ListGetExecutor.
-     * 
+     *
      * @param is the introspector
      * @param clazz the class to find the get method from
-     * @param identifier the key to use as an argument to the get method
+     * @param index the index to use as an argument to the get method
      * @return the executor if found, null otherwise
      */
-    public static ListGetExecutor discover(Introspector is, Class<?> clazz, Object identifier) {
-        java.lang.reflect.Method method = null;
-        Integer index = toInteger(identifier);
+    public static ListGetExecutor discover(Introspector is, Class<?> clazz, Integer index) {
         if (index != null) {
             if (clazz.isArray()) {
-                method = ARRAY_GET;
-            } else if (List.class.isAssignableFrom(clazz)) {
-                method = LIST_GET;
+                return new ListGetExecutor(clazz, ARRAY_GET, index);
+            }
+            if (List.class.isAssignableFrom(clazz)) {
+                return new ListGetExecutor(clazz, LIST_GET, index);
             }
         }
-        return method == null ? null : new ListGetExecutor(clazz, method, index);
+        return null;
     }
 
     /**
      * Creates an instance.
      * @param clazz he class the get method applies to
      * @param method the method held by this executor
-     * @param identifier the property to get
+     * @param index the index to use as an argument to the get method
      */
-    private ListGetExecutor(Class<?> clazz, java.lang.reflect.Method method, Integer identifier) {
+    private ListGetExecutor(Class<?> clazz, java.lang.reflect.Method method, Integer index) {
         super(clazz, method);
-        property = identifier;
+        property = index;
     }
 
     @Override
@@ -80,8 +79,8 @@ public final class ListGetExecutor exten
     }
 
     @Override
-    public Object tryInvoke(final Object obj, Object key) {
-        Integer index = toInteger(key);
+    public Object tryInvoke(final Object obj, Object identifier) {
+        Integer index = castInteger(identifier);
         if (obj != null && method != null
             && objectClass.equals(obj.getClass())
             && index != null) {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListSetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListSetExecutor.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListSetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/ListSetExecutor.java Mon Nov 25 13:35:55 2013
@@ -35,7 +35,7 @@ public final class ListSetExecutor exten
 
     /**
      * Attempts to discover a ListSetExecutor.
-     * 
+     *
      * @param is the introspector
      * @param clazz the class to find the get method from
      * @param identifier the key to use as an argument to the get method
@@ -43,8 +43,7 @@ public final class ListSetExecutor exten
      * @return the executor if found, null otherwise
      */
     public static ListSetExecutor discover(Introspector is, Class<?> clazz, Object identifier, Object value) {
-        Integer index = toInteger(identifier);
-        java.lang.reflect.Method method = null;
+        Integer index = castInteger(identifier);
         if (index != null) {
             if (clazz.isArray()) {
                 // we could verify if the call can be performed but it does not change
@@ -52,18 +51,19 @@ public final class ListSetExecutor exten
                 // Class<?> formal = clazz.getComponentType();
                 // Class<?> actual = value == null? Object.class : value.getClass();
                 // if (IntrospectionUtils.isMethodInvocationConvertible(formal, actual, false)) {
-                method = ARRAY_SET;
+                return new ListSetExecutor(clazz, ARRAY_SET, index);
                 // }
-            } else if (List.class.isAssignableFrom(clazz)) {
-                method = LIST_SET;
+            }
+            if (List.class.isAssignableFrom(clazz)) {
+                return new ListSetExecutor(clazz, LIST_SET, index);
             }
         }
-        return method == null ? null : new ListSetExecutor(clazz, method, index);
+        return null;
     }
 
     /**
      * Creates an instance.
-     * 
+     *
      * @param clazz the class the set method applies to
      * @param method the method called through this executor
      * @param key the key to use as 1st argument to the set method
@@ -92,7 +92,7 @@ public final class ListSetExecutor exten
 
     @Override
     public Object tryInvoke(final Object obj, Object key, Object value) {
-        Integer index = toInteger(key);
+        Integer index = castInteger(key);
         if (obj != null && method != null
                 && objectClass.equals(obj.getClass())
                 && index != null) {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapGetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapGetExecutor.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapGetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapGetExecutor.java Mon Nov 25 13:35:55 2013
@@ -32,7 +32,7 @@ public final class MapGetExecutor extend
 
     /**
      * Attempts to discover a MapGetExecutor.
-     * 
+     *
      * @param is the introspector
      * @param clazz the class to find the get method from
      * @param identifier the key to use as an argument to the get method

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MapSetExecutor.java Mon Nov 25 13:35:55 2013
@@ -31,7 +31,7 @@ public final class MapSetExecutor extend
 
     /**
      * Attempts to discover a MapSetExecutor.
-     * 
+     *
      * @param is the introspector
      * @param clazz the class to find the set method from
      * @param identifier the key to use as an argument to the get method
@@ -45,7 +45,7 @@ public final class MapSetExecutor extend
             return null;
         }
     }
-    
+
     /**
      * Creates an instance.
      * @param clazz the class the set method applies to
@@ -61,7 +61,7 @@ public final class MapSetExecutor extend
     public Object getTargetProperty() {
         return property;
     }
-    
+
     @Override
     public Object invoke(final Object obj, Object value) throws IllegalAccessException, InvocationTargetException {
         @SuppressWarnings("unchecked") // ctor only allows Map instances - see discover() method

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=1545274&r1=1545273&r2=1545274&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 Mon Nov 25 13:35:55 2013
@@ -24,9 +24,10 @@ import java.lang.reflect.InvocationTarge
  * @since 2.0
  */
 public final class MethodExecutor extends AbstractExecutor.Method {
-    /** Whether this method handles varargs. */
-    private final boolean isVarArgs;
-
+    /** If this method is a vararg method, vaStart is the last argument index. */
+    private final int vaStart;
+    /** If this method is a vararg method, vaClass is the component type of the vararg array. */
+    private final Class<?> vaClass;
 
     /**
      * Discovers a {@link MethodExecutor}.
@@ -66,18 +67,24 @@ public final class MethodExecutor extend
      */
     private MethodExecutor(Class<?> c, java.lang.reflect.Method m, MethodKey k) {
         super(c, m, k);
-        isVarArgs = method != null && isVarArgMethod(method);
+        int vastart = -1;
+        Class<?> vaclass = null;
+        if (method != null) {
+            Class<?>[] formal = method.getParameterTypes();
+            // if the last parameter is an array, the method is considered as vararg
+            if (formal != null && method.isVarArgs()) {
+                vastart = formal.length - 1;
+                vaclass = formal[vastart].getComponentType();
+            }
+        }
+        vaStart = vastart;
+        vaClass = vaclass;
     }
 
     @Override
     public Object invoke(Object o, Object[] args) throws IllegalAccessException, InvocationTargetException  {
-        if (isVarArgs) {
-            Class<?>[] formal = method.getParameterTypes();
-            int index = formal.length - 1;
-            Class<?> type = formal[index].getComponentType();
-            if (args.length >= index) {
-                args = handleVarArg(type, index, args);
-            }
+        if (vaClass != null) {
+            args = handleVarArg(args);
         }
         if (method.getDeclaringClass() == ArrayListWrapper.class && o.getClass().isArray()) {
             return method.invoke(new ArrayListWrapper(o), args);
@@ -111,62 +118,45 @@ public final class MethodExecutor extend
      * @param index  The index of the vararg in the method declaration
      *               (This will always be one less than the number of
      *               expected arguments.)
-     * @param actual The actual parameters being passed to this method
+     * @param actual The actual arguments being passed to this method
      * @return The actual parameters adjusted for the varargs in order
      * to fit the method declaration.
      */
-    private Object[] handleVarArg(Class<?> type, int index, Object[] actual) {
-        final int size = actual.length - index;
+    @SuppressWarnings("SuspiciousSystemArraycopy")
+    private Object[] handleVarArg(Object[] actual) {
+        final Class<?> vaclass = vaClass;
+        final int vastart = vaStart;
+        // variable arguments count
+        final int varargc = actual.length - vastart;
         // if no values are being passed into the vararg, size == 0
-        if (size == 1) {
+        if (varargc == 1) {
             // if one non-null value is being passed into the vararg,
             // and that arg is not the sole argument and not an array of the expected type,
             // make the last arg an array of the expected type
-            if (actual[index] != null) {
-                Class<?> aclazz = actual[index].getClass();
-                if (!aclazz.isArray() || !type.isAssignableFrom(aclazz.getComponentType())) {
+            if (actual[vastart] != null) {
+                Class<?> aclazz = actual[vastart].getClass();
+                if (!aclazz.isArray() || !vaclass.isAssignableFrom(aclazz.getComponentType())) {
                     // create a 1-length array to hold and replace the last argument
-                    Object lastActual = Array.newInstance(type, 1);
-                    Array.set(lastActual, 0, actual[index]);
-                    actual[index] = lastActual;
+                    Object lastActual = Array.newInstance(vaclass, 1);
+                    Array.set(lastActual, 0, actual[vastart]);
+                    actual[vastart] = lastActual;
                 }
             }
             // else, the vararg is null and used as is, considered as T[]
         } else {
             // if no or multiple values are being passed into the vararg,
             // put them in an array of the expected type
-            Object lastActual = Array.newInstance(type, size);
-            for (int i = 0; i < size; i++) {
-                Array.set(lastActual, i, actual[index + i]);
-            }
-
+            Object varargs = Array.newInstance(vaclass, varargc);
+            System.arraycopy(actual, vastart, varargs, 0, varargc);
             // put all arguments into a new actual array of the appropriate size
-            Object[] newActual = new Object[index + 1];
-            System.arraycopy(actual, 0, newActual, 0, index);
-            newActual[index] = lastActual;
-
+            Object[] newActual = new Object[vastart + 1];
+            System.arraycopy(actual, 0, newActual, 0, vastart);
+            newActual[vastart] = varargs;
             // replace the old actual array
             actual = newActual;
         }
         return actual;
     }
-
-   /**
-     * Determines if a method can accept a variable number of arguments.
-     * @param m a the method to check
-     * @return true if method is vararg, false otherwise
-     */
-    private static boolean isVarArgMethod(java.lang.reflect.Method m) {
-        Class<?>[] formal = m.getParameterTypes();
-        if (formal == null || formal.length == 0) {
-            return false;
-        } else {
-            Class<?> last = formal[formal.length - 1];
-            // if the last arg is an array, then
-            // we consider this a varargs method
-            return last.isArray();
-        }
-    }
 }
 
 

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java Mon Nov 25 13:35:55 2013
@@ -49,7 +49,6 @@ public final class MethodKey {
     private static final int PRIMITIVE_SIZE = 13;
     /** The primitive type to class conversion map. */
     private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPES;
-
     static {
         PRIMITIVE_TYPES = new HashMap<Class<?>, Class<?>>(PRIMITIVE_SIZE);
         PRIMITIVE_TYPES.put(Boolean.TYPE, Boolean.class);
@@ -78,7 +77,6 @@ public final class MethodKey {
         Class<?> prim = PRIMITIVE_TYPES.get(parm);
         return prim == null ? parm : prim;
     }
-
     /** The hash code. */
     private final int hashCode;
     /** The method name. */
@@ -93,7 +91,7 @@ public final class MethodKey {
     /**
      * Creates a key from a method name and a set of arguments.
      * @param aMethod the method to generate the key from
-     * @param args the intended method arguments
+     * @param args    the intended method arguments
      */
     public MethodKey(String aMethod, Object[] args) {
         super();
@@ -136,7 +134,7 @@ public final class MethodKey {
     /**
      * Creates a key from a method name and a set of parameters.
      * @param aMethod the method to generate the key from
-     * @param args the intended method parameters
+     * @param args    the intended method parameters
      */
     MethodKey(String aMethod, Class<?>[] args) {
         super();
@@ -257,9 +255,7 @@ public final class MethodKey {
      *         type or an object type of a primitive type that can be converted to
      *         the formal type.
      */
-    public static boolean isInvocationConvertible(Class<?> formal,
-            Class<?> actual,
-            boolean possibleVarArg) {
+    public static boolean isInvocationConvertible(Class<?> formal, Class<?> actual, boolean possibleVarArg) {
         /* if it's a null, it means the arg was null */
         if (actual == null && !formal.isPrimitive()) {
             return true;
@@ -270,6 +266,11 @@ public final class MethodKey {
             return true;
         }
 
+        /** Catch all... */
+        if (formal == Object.class) {
+            return true;
+        }
+
         /* Check for boxing with widening primitive conversion. Note that
          * actual parameters are never primitives. */
         if (formal.isPrimitive()) {
@@ -315,8 +316,7 @@ public final class MethodKey {
             if (actual != null && actual.isArray()) {
                 actual = actual.getComponentType();
             }
-            return isInvocationConvertible(formal.getComponentType(),
-                    actual, false);
+            return isInvocationConvertible(formal.getComponentType(), actual, false);
         }
         return false;
     }
@@ -337,16 +337,14 @@ public final class MethodKey {
      *         or formal and actual are both primitive types and actual can be
      *         subject to widening conversion to formal.
      */
-    public static boolean isStrictInvocationConvertible(Class<?> formal,
-            Class<?> actual,
-            boolean possibleVarArg) {
+    public static boolean isStrictInvocationConvertible(Class<?> formal, Class<?> actual, boolean possibleVarArg) {
         /* we shouldn't get a null into, but if so */
         if (actual == null && !formal.isPrimitive()) {
             return true;
         }
 
         /* Check for identity or widening reference conversion */
-        if (formal.isAssignableFrom(actual)) {
+        if (formal.isAssignableFrom(actual) && (formal.isArray() == actual.isArray())) {
             return true;
         }
 
@@ -382,8 +380,7 @@ public final class MethodKey {
             if (actual != null && actual.isArray()) {
                 actual = actual.getComponentType();
             }
-            return isStrictInvocationConvertible(formal.getComponentType(),
-                    actual, false);
+            return isStrictInvocationConvertible(formal.getComponentType(), actual, false);
         }
         return false;
     }
@@ -402,7 +399,7 @@ public final class MethodKey {
 
     /**
      * Simple distinguishable exception, used when
-     * we run across ambiguous overloading.  Caught
+     * we run across ambiguous overloading. Caught
      * by the introspector.
      */
     public static class AmbiguousException extends RuntimeException {
@@ -424,6 +421,8 @@ public final class MethodKey {
          */
         protected abstract Class<?>[] getParameterTypes(T app);
 
+        protected abstract boolean isVarArgs(T app);
+
         // CSOFF: RedundantThrows
         /**
          * Gets the most specific method that is applicable to actual argument types.<p>
@@ -580,7 +579,7 @@ public final class MethodKey {
         /**
          * Checks whether a parameter class is a primitive.
          * @param c the parameter class
-         * @param possibleVararg true if this is the last parameter which can tbe be a primitive array (vararg call)
+         * @param possibleVararg true if this is the last parameter which can be a primitive array (vararg call)
          * @return true if primitive, false otherwise
          */
         private boolean isPrimitive(Class<?> c,  boolean possibleVarArg) {
@@ -610,7 +609,6 @@ public final class MethodKey {
                 if (isApplicable(method, classes)) {
                     list.add(method);
                 }
-
             }
             return list;
         }
@@ -623,48 +621,62 @@ public final class MethodKey {
          * @param classes arguments to method
          * @return true if method is applicable to arguments
          */
-        private boolean isApplicable(T method, Class<?>[] classes) {
-            Class<?>[] methodArgs = getParameterTypes(method);
-            // if samee number or args or
+        private boolean isApplicable(T method, Class<?>[] actuals) {
+            Class<?>[] formals = getParameterTypes(method);
+            // if same number or args or
             // there's just one more methodArg than class arg
             // and the last methodArg is an array, then treat it as a vararg
-            if (methodArgs.length == classes.length
-                || ((methodArgs.length == classes.length + 1) && methodArgs[methodArgs.length - 1].isArray())) {
+            if (formals.length == actuals.length) {
                 // this will properly match when the last methodArg
                 // is an array/varargs and the last class is the type of array
                 // (e.g. String when the method is expecting String...)
-                for (int i = 0; i < classes.length; ++i) {
-                    if (!isConvertible(methodArgs[i], classes[i], false)) {
+                for (int i = 0; i < actuals.length; ++i) {
+                    if (!isConvertible(formals[i], actuals[i], false)) {
                         // if we're on the last arg and the method expects an array
-                        if (i == classes.length - 1 && methodArgs[i].isArray()) {
+                        if (i == actuals.length - 1 && formals[i].isArray()) {
                             // check to see if the last arg is convertible
                             // to the array's component type
-                            return isConvertible(methodArgs[i], classes[i], true);
+                            return isConvertible(formals[i], actuals[i], true);
                         }
                         return false;
                     }
                 }
                 return true;
             }
-            // more arguments given than the method accepts; check for varargs
-            if (methodArgs.length > 0 && classes.length > 0) {
-                // check that the last methodArg is an array
-                Class<?> lastarg = methodArgs[methodArgs.length - 1];
-                if (!lastarg.isArray()) {
+
+            // number of formal and actual differ, method must be vararg
+            if (!isVarArgs(method)) {
+                return false;
+            }
+
+            // less arguments than method parameters: vararg is null
+            if (formals.length > actuals.length) {
+                // only one parameter, the last (ie vararg) can be missing
+                if (formals.length - actuals.length > 1) {
                     return false;
                 }
+                // check that all present args match up to the method parms
+                for (int i = 0; i < actuals.length; ++i) {
+                    if (!isConvertible(formals[i], actuals[i], false)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
 
+            // more arguments given than the method accepts; check for varargs
+            if (formals.length > 0 && actuals.length > 0) {
                 // check that they all match up to the last method arg
-                for (int i = 0; i < methodArgs.length - 1; ++i) {
-                    if (!isConvertible(methodArgs[i], classes[i], false)) {
+                for (int i = 0; i < formals.length - 1; ++i) {
+                    if (!isConvertible(formals[i], actuals[i], false)) {
                         return false;
                     }
                 }
-
                 // check that all remaining arguments are convertible to the vararg type
-                Class<?> vararg = lastarg.getComponentType();
-                for (int i = methodArgs.length - 1; i < classes.length; ++i) {
-                    if (!isConvertible(vararg, classes[i], false)) {
+                // (last parm is an array since method is vararg)
+                Class<?> vararg = formals[formals.length - 1].getComponentType();
+                for (int i = formals.length - 1; i < actuals.length; ++i) {
+                    if (!isConvertible(vararg, actuals[i], false)) {
                         return false;
                     }
                 }
@@ -697,7 +709,8 @@ public final class MethodKey {
          *                       in the method declaration
          * @return see isStrictMethodInvocationConvertible.
          */
-        private boolean isStrictConvertible(Class<?> formal, Class<?> actual, boolean possibleVarArg) {
+        private boolean isStrictConvertible(Class<?> formal, Class<?> actual,
+                boolean possibleVarArg) {
             // if we see Void.class, the argument was null
             return isStrictInvocationConvertible(formal, actual.equals(Void.class) ? null : actual, possibleVarArg);
         }
@@ -710,6 +723,10 @@ public final class MethodKey {
         protected Class<?>[] getParameterTypes(Method app) {
             return app.getParameterTypes();
         }
+        @Override
+        public boolean isVarArgs(Method app) {
+            return app.isVarArgs();
+        }
     };
     /**
      * The parameter matching service for constructors.
@@ -719,5 +736,9 @@ public final class MethodKey {
         protected Class<?>[] getParameterTypes(Constructor<?> app) {
             return app.getParameterTypes();
         }
+        @Override
+        public boolean isVarArgs(Constructor<?> app) {
+            return app.isVarArgs();
+        }
     };
 }

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=1545274&r1=1545273&r2=1545274&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 Mon Nov 25 13:35:55 2013
@@ -27,11 +27,11 @@ public final class PropertyGetExecutor e
     private static final Object[] EMPTY_PARAMS = {};
     /** The property. */
     private final String property;
-    
+
     /**
      * Discovers a PropertyGetExecutor.
      * <p>The method to be found should be named "get{P,p}property.</p>
-     * 
+     *
      * @param is the introspector
      * @param clazz the class to find the get method from
      * @param property the property name to find
@@ -41,7 +41,7 @@ public final class PropertyGetExecutor e
         java.lang.reflect.Method method = discoverGet(is, "get", clazz, property);
         return method == null? null : new PropertyGetExecutor(clazz, method, property);
     }
-    
+
     /**
      * Creates an instance.
      * @param clazz he class the get method applies to
@@ -57,7 +57,7 @@ public final class PropertyGetExecutor e
     public Object getTargetProperty() {
         return property;
     }
-    
+
     @Override
     public Object invoke(Object o)
         throws IllegalAccessException, InvocationTargetException {
@@ -67,7 +67,7 @@ public final class PropertyGetExecutor e
     @Override
     public Object tryInvoke(Object o, Object identifier) {
         if (o != null && method !=  null
-            && property.equals(toString(identifier))
+            && property.equals(castString(identifier))
             && objectClass.equals(o.getClass())) {
             try {
                 return method.invoke(o, (Object[]) null);
@@ -89,8 +89,11 @@ public final class PropertyGetExecutor e
      * @return The {get,is}{p,P}roperty method if one exists, null otherwise.
      */
     static java.lang.reflect.Method discoverGet(Introspector is, String which, Class<?> clazz, String property) {
+        if (property == null || property.isEmpty()) {
+            return null;
+        }
         //  this is gross and linear, but it keeps it straightforward.
-        java.lang.reflect.Method method = null;
+        java.lang.reflect.Method method;
         final int start = which.length(); // "get" or "is" so 3 or 2 for char case switch
         // start with get<Property>
         StringBuilder sb = new StringBuilder(which);

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=1545274&r1=1545273&r2=1545274&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 Mon Nov 25 13:35:55 2013
@@ -14,45 +14,48 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.jexl3.internal.introspection;
+
+import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 
 /**
  * Specialized executor to set a property in an object.
  * @since 2.0
  */
-public final class PropertySetExecutor extends AbstractExecutor.Set {
+public class PropertySetExecutor extends AbstractExecutor.Set {
     /** Index of the first character of the set{p,P}roperty. */
     private static final int SET_START_INDEX = 3;
     /** The property. */
-    private final String property;
-    
+    protected final String property;
+
     /**
      * Discovers a PropertySetExecutor.
      * <p>The method to be found should be named "set{P,p}property.</p>
-     * 
-     * @param is the introspector
-     * @param clazz the class to find the get method from
+     *
+     * @param is       the introspector
+     * @param clazz    the class to find the get method from
      * @param property the property name to find
-     * @param arg the value to assign to the property
+     * @param arg      the value to assign to the property
      * @return the executor if found, null otherwise
      */
     public static PropertySetExecutor discover(Introspector is, Class<?> clazz, String property, Object arg) {
+        if (property == null || property.isEmpty()) {
+            return null;
+        }
         java.lang.reflect.Method method = discoverSet(is, clazz, property, arg);
-        return method == null? null : new PropertySetExecutor(clazz, method, property);
+        return method != null? new PropertySetExecutor(clazz, method, property) : null;
     }
-    
+
     /**
      * Creates an instance.
-     * @param clazz the class the set method applies to
+     * @param clazz  the class the set method applies to
      * @param method the method called through this executor
-     * @param key the key to use as 1st argument to the set method
+     * @param key    the key to use as 1st argument to the set method
      */
-    private PropertySetExecutor(Class<?> clazz, java.lang.reflect.Method method, String key) {
+    protected PropertySetExecutor(Class<?> clazz, java.lang.reflect.Method method, String key) {
         super(clazz, method);
         property = key;
-
     }
 
     @Override
@@ -62,9 +65,17 @@ public final class PropertySetExecutor e
 
     @Override
     public Object invoke(Object o, Object arg) throws IllegalAccessException, InvocationTargetException {
-        Object[] pargs = {arg};
         if (method != null) {
-            method.invoke(o, pargs);
+            // handle the empty array case
+            if (isEmptyArray(arg)) {
+                // if array is empty but its component type is different from the method first parameter component type,
+                // replace argument with a new empty array instance (of the method first parameter component type)
+                Class<?> componentType = method.getParameterTypes()[0].getComponentType();
+                if (componentType != null && !componentType.equals(arg.getClass().getComponentType())) {
+                    arg = Array.newInstance(componentType, 0);
+                }
+            }
+            method.invoke(o, arg);
         }
         return arg;
     }
@@ -73,11 +84,9 @@ public final class PropertySetExecutor e
     public Object tryInvoke(Object o, Object identifier, Object arg) {
         if (o != null && method != null
             // ensure method name matches the property name
-            && property.equals(toString(identifier))
+            && property.equals(castString(identifier))
             // object class should be same as executor's method declaring class
-            && objectClass.equals(o.getClass())
-            // we are guaranteed the method has one parameter since it is a set(x)
-            && (arg == null || method.getParameterTypes()[0].equals(arg.getClass()))) {
+            && objectClass.equals(o.getClass())) {
             try {
                 return invoke(o, arg);
             } catch (InvocationTargetException xinvoke) {
@@ -89,15 +98,24 @@ public final class PropertySetExecutor e
         return TRY_FAILED;
     }
 
+    /**
+     * Checks wether an argument is an empty array.
+     * @param arg the argument
+     * @return true if <code>arg</code> is an empty array
+     */
+    private static boolean isEmptyArray(Object arg) {
+        return (arg != null && arg.getClass().isArray() && Array.getLength(arg) == 0);
+    }
 
     /**
      * Discovers the method for a {@link PropertySet}.
-     * <p>The method to be found should be named "set{P,p}property.</p>
-     * 
-     * @param is the introspector
-     * @param clazz the class to find the get method from
+     * <p>The method to be found should be named "set{P,p}property.
+     * As a special case, any empty array will try to find a valid array-setting non-ambiguous method.
+     *
+     * @param is       the introspector
+     * @param clazz    the class to find the get method from
      * @param property the name of the property to set
-     * @param arg the value to assign to the property
+     * @param arg      the value to assign to the property
      * @return the method if found, null otherwise
      */
     private static java.lang.reflect.Method discoverSet(Introspector is, Class<?> clazz, String property, Object arg) {
@@ -113,8 +131,44 @@ public final class PropertySetExecutor e
         if (method == null) {
             sb.setCharAt(SET_START_INDEX, Character.toLowerCase(c));
             method = is.getMethod(clazz, sb.toString(), params);
+            // uppercase nth char, try array
+            if (method == null && isEmptyArray(arg)) {
+                sb.setCharAt(SET_START_INDEX, Character.toUpperCase(c));
+                method = lookupSetEmptyArray(is, clazz, sb.toString());
+                // lowercase nth char
+                if (method == null) {
+                    sb.setCharAt(SET_START_INDEX, Character.toLowerCase(c));
+                    method = lookupSetEmptyArray(is, clazz, sb.toString());
+                }
+            }
         }
         return method;
     }
-}
 
+    /**
+     * Finds an empty array property setter method by <code>methodName</code>.
+     * <p>This checks only one method with that name accepts an array as sole parameter.
+     * @param is       the introspector
+     * @param clazz    the class to find the get method from
+     * @param methodName the method name to find
+     * @return         the sole method that accepts an array as parameter
+     */
+    private static java.lang.reflect.Method lookupSetEmptyArray(Introspector is, final Class<?> clazz, String methodName) {
+        java.lang.reflect.Method candidate = null;
+        java.lang.reflect.Method[] methods = is.getMethods(clazz, methodName);
+        if (methods != null) {
+            for (java.lang.reflect.Method method : methods) {
+                Class<?>[] paramTypes = method.getParameterTypes();
+                if (paramTypes.length == 1 && paramTypes[0].isArray()) {
+                    if (candidate != null) {
+                        // because the setter method is overloaded for different parameter type,
+                        // return null here to report the ambiguity.
+                        return null;
+                    }
+                    candidate = method;
+                }
+            }
+        }
+        return candidate;
+    }
+}

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=1545274&r1=1545273&r2=1545274&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 Mon Nov 25 13:35:55 2013
@@ -21,7 +21,7 @@ import org.apache.commons.jexl3.introspe
 import org.apache.commons.jexl3.introspection.JexlPropertySet;
 import org.apache.commons.jexl3.introspection.JexlUberspect;
 
-import org.apache.commons.logging.Log;
+import org.apache.log4j.Logger;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -47,7 +47,7 @@ public class Uberspect implements JexlUb
      */
     public static final Object TRY_FAILED = AbstractExecutor.TRY_FAILED;
     /** The logger to use for all warnings & errors. */
-    protected final Log rlog;
+    protected final Logger rlog;
     /** The introspector version. */
     private final AtomicInteger version;
     /** The soft reference to the introspector currently in use. */
@@ -59,7 +59,7 @@ public class Uberspect implements JexlUb
      * Creates a new Uberspect.
      * @param runtimeLogger the logger used for all logging needs
      */
-    public Uberspect(Log runtimeLogger) {
+    public Uberspect(Logger runtimeLogger) {
         rlog = runtimeLogger;
         ref = new SoftReference<Introspector>(null);
         loader = new SoftReference<ClassLoader>(getClass().getClassLoader());
@@ -120,7 +120,9 @@ public class Uberspect implements JexlUb
     }
 
     /**
-     * Gets the field named by <code>key</code> for the class <code>c</code>.
+     * Gets the field named by
+     * <code>key</code> for the class
+     * <code>c</code>.
      *
      * @param c   Class in which the field search is taking place
      * @param key Name of the field being searched for
@@ -140,29 +142,33 @@ public class Uberspect implements JexlUb
     }
 
     /**
-     * Gets the method defined by <code>name</code> and
-     * <code>params</code> for the Class <code>c</code>.
+     * Gets the method defined by
+     * <code>name</code> and
+     * <code>params</code> for the Class
+     * <code>c</code>.
      *
      * @param c      Class in which the method search is taking place
      * @param name   Name of the method being searched for
      * @param params An array of Objects (not Classes) that describe the
-     * the parameters
+     *               the parameters
      *
      * @return a {@link java.lang.reflect.Method}
-     * or null if no unambiguous method could be found through introspection.
+     *         or null if no unambiguous method could be found through introspection.
      */
     public final Method getMethod(Class<?> c, String name, Object[] params) {
         return base().getMethod(c, new MethodKey(name, params));
     }
 
     /**
-     * Gets the method defined by <code>key</code> and for the Class <code>c</code>.
+     * Gets the method defined by
+     * <code>key</code> and for the Class
+     * <code>c</code>.
      *
      * @param c   Class in which the method search is taking place
      * @param key MethodKey of the method being searched for
      *
      * @return a {@link java.lang.reflect.Method}
-     * or null if no unambiguous method could be found through introspection.
+     *         or null if no unambiguous method could be found through introspection.
      */
     public final Method getMethod(Class<?> c, MethodKey key) {
         return base().getMethod(c, key);
@@ -195,7 +201,7 @@ public class Uberspect implements JexlUb
     @Override
     public JexlPropertyGet getPropertyGet(Object obj, Object identifier) {
         final Class<?> claz = obj.getClass();
-        final String property = AbstractExecutor.toString(identifier);
+        final String property = AbstractExecutor.castString(identifier);
         final Introspector is = base();
         JexlPropertyGet executor;
         // first try for a getFoo() type of property (also getfoo() )
@@ -216,32 +222,38 @@ public class Uberspect implements JexlUb
             return executor;
         }
         // let's see if this is a list or array
-        executor = ListGetExecutor.discover(is, claz, identifier);
-        if (executor != null) {
-            return executor;
-        }
-        // if that didn't work, look for get(foo)
-        executor = DuckGetExecutor.discover(is, claz, identifier);
-        if (executor != null) {
-            return executor;
-        }
-        // last, look for get("foo") if we did not try yet
-        if (property != null && !(identifier instanceof String)) {
-            // if that didn't work, look for get("foo")
-            executor = DuckGetExecutor.discover(is, claz, property);
+        Integer index = AbstractExecutor.castInteger(identifier);
+        if (index != null) {
+            executor = ListGetExecutor.discover(is, claz, index);
             if (executor != null) {
                 return executor;
             }
         }
-        // a field may be?
-        executor = FieldGetExecutor.discover(is, claz, property);
+        // if that didn't work, look for get(foo)
+        executor = DuckGetExecutor.discover(is, claz, identifier);
         if (executor != null) {
             return executor;
         }
-        // or an indexed property?
-        executor = IndexedType.discover(is, obj, property);
-        if (executor != null) {
-            return executor;
+        if (property != null) {
+            // look for get("foo") if we did not try yet (just above)
+            if (property != identifier) {
+                executor = DuckGetExecutor.discover(is, claz, property);
+                if (executor != null) {
+                    return executor;
+                }
+            }
+            if (index == null) {
+                // a field may be? (can not be a number)
+                executor = FieldGetExecutor.discover(is, claz, property);
+                if (executor != null) {
+                    return executor;
+                }
+                // or an indexed property?
+                executor = IndexedType.discover(is, obj, property);
+                if (executor != null) {
+                    return executor;
+                }
+            }
         }
         return null;
     }
@@ -249,7 +261,7 @@ public class Uberspect implements JexlUb
     @Override
     public JexlPropertySet getPropertySet(final Object obj, final Object identifier, Object arg) {
         final Class<?> claz = obj.getClass();
-        final String property = AbstractExecutor.toString(identifier);
+        final String property = AbstractExecutor.castString(identifier);
         final Introspector is = base();
         JexlPropertySet executor;
         // first try for a setFoo() type of property (also setfoo() )
@@ -266,9 +278,12 @@ public class Uberspect implements JexlUb
         }
         // 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
-        executor = ListSetExecutor.discover(is, claz, identifier, arg);
-        if (executor != null) {
-            return executor;
+        Integer index = AbstractExecutor.castInteger(identifier);
+        if (index != null) {
+            executor = ListSetExecutor.discover(is, claz, identifier, arg);
+            if (executor != null) {
+                return executor;
+            }
         }
         // if that didn't work, look for set(foo)
         executor = DuckSetExecutor.discover(is, claz, identifier, arg);
@@ -276,16 +291,20 @@ public class Uberspect implements JexlUb
             return executor;
         }
         // last, look for set("foo") if we did not try yet
-        if (property != null && !(identifier instanceof String)) {
-            executor = DuckSetExecutor.discover(is, claz, property, arg);
-            if (executor != null) {
-                return executor;
+        if (property != null) {
+            if (property != identifier) {
+                executor = DuckSetExecutor.discover(is, claz, property, arg);
+                if (executor != null) {
+                    return executor;
+                }
+            }
+            if (index == null) {
+                // a field may be?
+                executor = FieldSetExecutor.discover(is, claz, property, arg);
+                if (executor != null) {
+                    return executor;
+                }
             }
-        }
-        // a field may be?
-        executor = FieldSetExecutor.discover(is, claz, property, arg);
-        if (executor != null) {
-            return executor;
         }
         return null;
     }
@@ -328,4 +347,63 @@ public class Uberspect implements JexlUb
     public JexlMethod getConstructor(Object ctorHandle, Object[] args) {
         return ConstructorMethod.discover(base(), ctorHandle, args);
     }
+    /**
+     * May be a way to extend/improve sandboxing by choosing actual method for resolution.
+     **
+     * public static enum GetResolver {
+     * PROPERTY {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return PropertyGetExecutor.discover(uberspect.base(), obj.getClass(), AbstractExecutor.toString(identifier));
+     * }
+     * },
+     * BOOLEAN {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return BooleanGetExecutor.discover(uberspect.base(), obj.getClass(), AbstractExecutor.toString(identifier));
+     * }
+     * },
+     * MAP {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return MapGetExecutor.discover(uberspect.base(), obj.getClass(), identifier);
+     * }
+     * },
+     * LIST {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return ListGetExecutor.discover(uberspect.base(), obj.getClass(), identifier);
+     * }
+     * },
+     * DUCK {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * final Introspector is = uberspect.base();
+     * final Class<?> clazz = obj.getClass();
+     * JexlPropertyGet executor = DuckGetExecutor.discover(is, clazz, identifier);
+     * if (executor == null && identifier != null && !(identifier instanceof String)) {
+     * executor = DuckGetExecutor.discover(is, clazz, AbstractExecutor.toString(identifier));
+     * }
+     * return executor;
+     * }
+     * },
+     * FIELD {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return FieldGetExecutor.discover(uberspect.base(), obj.getClass(), AbstractExecutor.toString(identifier));
+     * }
+     * },
+     * INDEXED {
+     * @Override
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return IndexedType.discover(uberspect.base(), obj, AbstractExecutor.toString(identifier));
+     * }
+     * },
+     * ANY {};
+     * <p/>
+     * public JexlPropertyGet resolve(Uberspect uberspect, Object obj, Object identifier) {
+     * return uberspect.getPropertyGet(obj, identifier);
+     * }
+     * }
+     */
 }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlMethod.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlMethod.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlMethod.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlMethod.java Mon Nov 25 13:35:55 2013
@@ -23,7 +23,7 @@ package org.apache.commons.jexl3.introsp
  * <code>
  * ${foo.bar()}
  * </code>
- * 
+ *
  * @since 1.0
  */
 public interface JexlMethod {
@@ -51,7 +51,8 @@ public interface JexlMethod {
     Object tryInvoke(String name, Object obj, Object[] params);
 
     /**
-     * Checks whether a tryInvoke failed or not.
+     * Checks whether a tryInvoke return value indicates a failure or not.
+     * <p>Usage is : <code>Object r = tryInvoke(...); if (tryFailed(r) {...} else {...}</code>
      * @param rval the value returned by tryInvoke
      * @return true if tryInvoke failed, false otherwise
      */
@@ -60,7 +61,7 @@ public interface JexlMethod {
     /**
      * Specifies if this JexlMethod is cacheable and able to be reused for this
      * class of object it was returned for.
-     * 
+     *
      * @return true if can be reused for this class, false if not
      */
     boolean isCacheable();

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertyGet.java Mon Nov 25 13:35:55 2013
@@ -28,7 +28,7 @@ package org.apache.commons.jexl3.introsp
 public interface JexlPropertyGet {
     /**
      * Method used to get the property value of an object.
-     * 
+     *
      * @param obj the object to get the property value from.
      * @return the property value.
      * @throws Exception on any error.

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertySet.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertySet.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertySet.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/introspection/JexlPropertySet.java Mon Nov 25 13:35:55 2013
@@ -28,7 +28,7 @@ package org.apache.commons.jexl3.introsp
 public interface JexlPropertySet {
     /**
      * Method used to set the property value of an object.
-     * 
+     *
      * @param obj Object on which the property setter will be called with the value
      * @param arg value to be set
      * @return the value returned from the set operation (impl specific)
@@ -53,11 +53,11 @@ public interface JexlPropertySet {
      * @return true if tryInvoke failed, false otherwise
      */
     boolean tryFailed(Object rval);
-    
+
     /**
      * Specifies if this JexlPropertySet is cacheable and able to be reused for
      * this class of object it was returned for.
-     * 
+     *
      * @return true if can be reused for this class, false if not
      */
     boolean isCacheable();

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTArrayLiteral.java Mon Nov 25 13:35:55 2013
@@ -41,8 +41,7 @@ public final class ASTArrayLiteral exten
         return constant;
     }
 
-    /** {
-     * @inheritDoc} */
+    /** {@inheritDoc} */
     @Override
     public void jjtClose() {
         constant = true;
@@ -58,8 +57,7 @@ public final class ASTArrayLiteral exten
         }
     }
 
-    /** {
-     * @inheritDoc} */
+    /** {@inheritDoc} */
     @Override
     public Object jjtAccept(ParserVisitor visitor, Object data) {
         return visitor.visit(this, data);

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlLambda.java Mon Nov 25 13:35:55 2013
@@ -19,7 +19,7 @@ package org.apache.commons.jexl3.parser;
 import org.apache.commons.jexl3.internal.Scope;
 
 /**
- * Enhanced script to allow parameters declaration.
+ * Lambda (function).
  */
 public final class ASTJexlLambda extends ASTJexlScript {
     ASTJexlLambda(int id) {
@@ -30,6 +30,10 @@ public final class ASTJexlLambda extends
         super(p, id);
     }
 
+    public boolean isTopLevel() {
+        return parent == null;
+    }
+
     /**
      * Creates an array of arguments by copying values up to the number of parameters.
      * @param values the argument values

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTJexlScript.java Mon Nov 25 13:35:55 2013
@@ -33,6 +33,20 @@ public class ASTJexlScript extends JexlN
         super(p, id);
     }
 
+    /**
+     * Consider script with no parameters that return lambda as parametric-scripts.
+     * @return the script
+     */
+    public ASTJexlScript script() {
+        if (scope == null && children != null && children.length == 1 && children[0] instanceof ASTJexlLambda) {
+            ASTJexlLambda lambda = (ASTJexlLambda) children[0];
+            lambda.parent = null;
+            return lambda;
+        } else {
+            return this;
+        }
+    }
+
     @Override
     public Object jjtAccept(ParserVisitor visitor, Object data) {
         return visitor.visit(this, data);

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTNumberLiteral.java Mon Nov 25 13:35:55 2013
@@ -38,25 +38,27 @@ public final class ASTNumberLiteral exte
 
     @Override
     public String toString() {
+        if (literal == null || clazz == null || Double.isNaN(literal.doubleValue())) {
+            return "NaN";
+        }
         if (BigDecimal.class.equals(clazz)) {
               return BIGDF.format(literal);
-        } else {
-            StringBuilder strb = new StringBuilder(literal.toString());
-            if (clazz != null) {
-                if (Float.class.equals(clazz)) {
-                    strb.append('f');
-                } else if (Double.class.equals(clazz)) {
-                    strb.append('d');
-                } else if (BigDecimal.class.equals(clazz)) {
-                    strb.append('b');
-                } else if (BigInteger.class.equals(clazz)) {
-                    strb.append('h');
-                } else if (Long.class.equals(clazz)) {
-                    strb.append('l');
-                }
+        }
+        StringBuilder strb = new StringBuilder(literal.toString());
+        if (clazz != null) {
+            if (Float.class.equals(clazz)) {
+                strb.append('f');
+            } else if (Double.class.equals(clazz)) {
+                strb.append('d');
+            } else if (BigDecimal.class.equals(clazz)) {
+                strb.append('b');
+            } else if (BigInteger.class.equals(clazz)) {
+                strb.append('h');
+            } else if (Long.class.equals(clazz)) {
+                strb.append('l');
             }
-            return strb.toString();
         }
+        return strb.toString();
     }
 
     @Override
@@ -136,7 +138,7 @@ public final class ASTNumberLiteral exte
     void setReal(String s) {
         Number result;
         Class<?> rclass;
-        if ("#NaN".equals(s)) {
+        if ("#NaN".equals(s) || "NaN".equals(s)) {
             result = Double.NaN;
             rclass = Double.class;
         } else {

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTVar.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTVar.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTVar.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/ASTVar.java Mon Nov 25 13:35:55 2013
@@ -27,7 +27,7 @@ public class ASTVar extends ASTIdentifie
     public ASTVar(Parser p, int id) {
         super(p, id);
     }
-    
+
     @Override
     public Object jjtAccept(ParserVisitor visitor, Object data) {
         return visitor.visit(this, data);

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt Mon Nov 25 13:35:55 2013
@@ -38,7 +38,7 @@ import org.apache.commons.jexl3.internal
 
 public final class Parser extends JexlParser
 {
-    public ASTJexlScript parse(JexlInfo info, String jexlSrc, Scope scope, boolean registers) {
+    public ASTJexlScript parse(JexlInfo info, String jexlSrc, Scope scope, boolean registers, boolean expr) {
         try {
             // If registers are allowed, the default parser state has to be REGISTERS.
             if (registers || ALLOW_REGISTERS) {
@@ -48,7 +48,7 @@ public final class Parser extends JexlPa
             source = jexlSrc;
             ReInit(new java.io.StringReader(jexlSrc));
             frame = scope;
-            ASTJexlScript script = JexlScript(scope);
+            ASTJexlScript script = expr? JexlExpression(scope) : JexlScript(scope) ;
             script.value = info;
             return script;
         } catch (TokenMgrError xtme) {
@@ -159,6 +159,10 @@ PARSER_END(Parser)
 /***************************************
  *     Identifier & String tokens
  ***************************************/
+<*> TOKEN :  /* NaN */
+{
+    < NAN_LITERAL : "NaN" >
+}
 
 <*> TOKEN : /* IDENTIFIERS */
 {
@@ -205,7 +209,19 @@ ASTJexlScript JexlScript(Scope frame) : 
 }
 {
    ( Statement() )* <EOF>
-   { return jjtThis;}
+   {
+        return jjtThis.script();
+   }
+}
+
+ASTJexlScript JexlExpression(Scope frame) #JexlScript : {
+    jjtThis.setScope(frame);
+}
+{
+   ( Expression() )? <EOF>
+   {
+        return jjtThis.script();
+   }
 }
 
 void Statement() #void : {}
@@ -452,6 +468,14 @@ void Literal() #void :
   StringLiteral()
 |
   NullLiteral()
+|
+  NaNLiteral()
+}
+
+void NaNLiteral() #NumberLiteral :
+{}
+{
+    <NAN_LITERAL> { jjtThis.setReal("NaN"); }
 }
 
 void NullLiteral() : {}
@@ -535,6 +559,15 @@ void Arguments() #Arguments : {}
      <LPAREN> (Expression() (<COMMA> Expression())* )? <RPAREN>
 }
 
+void FunctionCallLookahead() #void : {}
+{
+    LOOKAHEAD(4) <IDENTIFIER> <COLON> <IDENTIFIER> <LPAREN>
+    |
+    LOOKAHEAD(2) <IDENTIFIER> <LPAREN>
+    |
+    LOOKAHEAD(2) <REGISTER> <LPAREN>
+}
+
 void FunctionCall() #void : {}
 {
       LOOKAHEAD(2) Identifier() <COLON> Identifier() Arguments() #FunctionNode(3)
@@ -627,7 +660,7 @@ void PrimaryExpression() #void : {}
     |
        LOOKAHEAD( <NEW> ) Constructor()
     |
-       LOOKAHEAD(2) FunctionCall()
+       LOOKAHEAD( FunctionCallLookahead() ) FunctionCall()
     |
        Identifier(true)
     |

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/StringParser.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/StringParser.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/StringParser.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/parser/StringParser.java Mon Nov 25 13:35:55 2013
@@ -205,5 +205,5 @@ public class StringParser {
         strb.append(delim);
         return strb.toString();
     }
-    
+
 }
\ No newline at end of file

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/JexlScriptEngine.java Mon Nov 25 13:35:55 2013
@@ -38,8 +38,8 @@ import org.apache.commons.jexl3.JexlCont
 import org.apache.commons.jexl3.JexlEngine;
 import org.apache.commons.jexl3.JexlScript;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.log4j.Logger;
+import org.apache.log4j.LogManager;
 
 /**
  * Implements the Jexl ScriptEngine for JSF-223.
@@ -62,7 +62,7 @@ import org.apache.commons.logging.LogFac
  */
 public class JexlScriptEngine extends AbstractScriptEngine implements Compilable {
     /** The logger. */
-    private static final Log LOG = LogFactory.getLog(JexlScriptEngine.class);
+    private static final Logger LOG = LogManager.getLogger(JexlScriptEngine.class);
 
     /** The shared expression cache size. */
     private static final int CACHE_SIZE = 512;
@@ -169,7 +169,7 @@ public class JexlScriptEngine extends Ab
          * Gives access to the engine logger.
          * @return the JexlScriptEngine logger
          */
-        public Log getLogger() {
+        public Logger getLogger() {
             return LOG;
         }
     }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/Main.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/Main.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/Main.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/scripting/Main.java Mon Nov 25 13:35:55 2013
@@ -32,16 +32,16 @@ public class Main {
 
     /**
      * Test application for JexlScriptEngine (JSR-223 implementation).
-     * 
+     *
      * If a single argument is present, it is treated as a filename of a JEXL
      * script to be evaluated. Any exceptions terminate the application.
-     * 
+     *
      * Otherwise, lines are read from standard input and evaluated.
      * ScriptExceptions are logged, and do not cause the application to exit.
      * This is done so that interactive testing is easier.
-     * 
+     *
      * @param args (optional) filename to evaluate. Stored in the args variable.
-     * 
+     *
      * @throws Exception if parsing or IO fail
      */
     public static void main(String[] args) throws Exception {

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=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/jexl/trunk/src/site/xdoc/changes.xml Mon Nov 25 13:35:55 2013
@@ -25,7 +25,55 @@
         <author email="dev@commons.apache.org">Commons Developers</author>
     </properties>
     <body>
-        <release version="3.0" date="2012-09-30">
+        <release version="3.0.1" date="unreleased">
+            <action dev="henrib" type="fix" >
+                Fixed issue in edge case method resolution wrt overload and varargs
+            </action>
+            <action dev="henrib" type="add" >
+                Switch logging to log4j 1.2
+            </action>
+            <action dev="henrib" type="fix" issue="JEXL-144" due-to="Woonsang Ko">
+                Empty array property setting fails
+            </action>
+            <action dev="henrib" type="fix" issue="JEXL-142" due-to="Juozas Baliuks">
+                Map expression issue with empty key
+            </action>
+            <action dev="henrib" type="fix" issue="JEXL-141" due-to="Harpreet Singh">
+                Suffix for Big Decimal and Big Integer Literal is incorrectly mentioned in Java docs
+            </action>
+            <action dev="henrib" type="fix" issue="JEXL-137">
+                Invalid script variable list for nested array/map access
+            </action>
+            <action dev="henrib" type="fix">
+                Fixed Engine.getVariables that was erroneously considering method calls as variable usage
+            </action>
+            <action dev="henrib" type="fix">
+                Fixed issue in ternary expression
+                (grammar was not precise enough to differentiate namespace:function calls vs ternary right hand side)
+            </action>
+            <action dev="henrib" type="add">
+                NaN is now a keyword equivalent to #NaN (deprecated): POTENTIAL SCRIPT BREAK!
+            </action>
+            <action dev="henrib" type="add">
+                Syntactically enforce that expressions do not contain statements: POTENTIAL EXPRESSION BREAK!
+                (ie an expression is not a script and can NOT use 'if','for'... and blocks)
+            </action>
+           <action dev="henrib" type="add">
+                Added syntactic shortcut to create parametric scripts (script source creates an anonymous function)
+            </action>
+            <action dev="henrib" type="fix">
+                Segregated JexlScript and JexlExpression further to avoid calling JexlExpression.evaluate on JexlScript
+                (instead of JexlScript.execute) which had the unexpected property of only evaluating the first statement
+            </action>
+            <action dev="henrib" type="fix">
+                Fix an edge case of ambiguous method matching (see http://apache-commons.680414.n4.nabble.com/jexl-mathod-within-namespace-not-found-if-parameter-is-int-tt4637888.html)
+            </action>
+            <action dev="henrib" type="fix">
+                Fix issue wrt isEmpty and method varargs (assignable types vs equal types)
+                (see http://apache-commons.680414.n4.nabble.com/jexl-empty-function-crashes-if-called-with-int-tt4637895.html)
+            </action>
+        </release>
+        <release version="3.0" date="unreleased">
             <action dev="henrib" type="add" issue="JEXL-133" due-to="Alfred Reibenschuh">
                 String matching Operator short-hand inspired by CSS3
             </action>

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java Mon Nov 25 13:35:55 2013
@@ -352,9 +352,15 @@ public class ArithmeticTest extends Jexl
         script = jexl.createScript("#NaN");
         result = script.execute(null);
         assertTrue(Double.isNaN((Double) result));
+        script = jexl.createScript("NaN");
+        result = script.execute(null);
+        assertTrue(Double.isNaN((Double) result));
         script = jexl.createScript("double:isNaN(#NaN)");
         result = script.execute(null);
         assertTrue((Boolean) result);
+        script = jexl.createScript("double:isNaN(NaN)");
+        result = script.execute(null);
+        assertTrue((Boolean) result);
     }
 
     public static class EmptyTestContext extends MapContext implements JexlContext.NamespaceResolver {
@@ -405,4 +411,4 @@ public class ArithmeticTest extends Jexl
             assertEquals("failed on " + stext, expected, result);
         }
     }
-}
+}
\ No newline at end of file

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayLiteralTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayLiteralTest.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayLiteralTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ArrayLiteralTest.java Mon Nov 25 13:35:55 2013
@@ -27,7 +27,7 @@ public class ArrayLiteralTest extends Je
     public ArrayLiteralTest() {
         super("ArrayLiteralTest");
     }
-    
+
     public void testLiteralWithStrings() throws Exception {
         JexlExpression e = JEXL.createExpression( "[ 'foo' , 'bar' ]" );
         JexlContext jc = new MapContext();
@@ -63,7 +63,7 @@ public class ArrayLiteralTest extends Je
             "[ 10 , null , 10]",
             "[ '10' , null ]",
             "[ null, '10' , null ]"
-        }; 
+        };
         Object [][]checks = {
             {null, new Integer(10)},
             {new Integer(10), null},

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BitwiseOperatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BitwiseOperatorTest.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BitwiseOperatorTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BitwiseOperatorTest.java Mon Nov 25 13:35:55 2013
@@ -38,7 +38,7 @@ public class BitwiseOperatorTest extends
     public BitwiseOperatorTest(String name) {
         super(name);
     }
-    
+
     public void testAndWithTwoNulls() throws Exception {
         asserter.assertExpression("null & null", new Long(0));
     }
@@ -70,7 +70,7 @@ public class BitwiseOperatorTest extends
     public void testComplementWithNull() throws Exception {
         asserter.assertExpression("~null", new Long(-1));
     }
-    
+
     public void testComplementSimple() throws Exception {
         asserter.assertExpression("~128", new Long(-129));
     }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BlockTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BlockTest.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BlockTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/BlockTest.java Mon Nov 25 13:35:55 2013
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,7 +24,7 @@ public class BlockTest extends JexlTestC
 
     /**
      * Create the test
-     * 
+     *
      * @param testName name of the test
      */
     public BlockTest(String testName) {
@@ -32,46 +32,46 @@ public class BlockTest extends JexlTestC
     }
 
     public void testBlockSimple() throws Exception {
-        JexlExpression e = JEXL.createExpression("if (true) { 'hello'; }");
+        JexlScript e = JEXL.createScript("if (true) { 'hello'; }");
         JexlContext jc = new MapContext();
-        Object o = e.evaluate(jc);
+        Object o = e.execute(jc);
         assertEquals("Result is wrong", "hello", o);
     }
 
     public void testBlockExecutesAll() throws Exception {
-        JexlExpression e = JEXL.createExpression("if (true) { x = 'Hello'; y = 'World';}");
+        JexlScript e = JEXL.createScript("if (true) { x = 'Hello'; y = 'World';}");
         JexlContext jc = new MapContext();
-        Object o = e.evaluate(jc);
+        Object o = e.execute(jc);
         assertEquals("First result is wrong", "Hello", jc.get("x"));
         assertEquals("Second result is wrong", "World", jc.get("y"));
         assertEquals("Block result is wrong", "World", o);
     }
 
     public void testEmptyBlock() throws Exception {
-        JexlExpression e = JEXL.createExpression("if (true) { }");
+        JexlScript e = JEXL.createScript("if (true) { }");
         JexlContext jc = new MapContext();
-        Object o = e.evaluate(jc);
+        Object o = e.execute(jc);
         assertNull("Result is wrong", o);
     }
 
     public void testBlockLastExecuted01() throws Exception {
-        JexlExpression e = JEXL.createExpression("if (true) { x = 1; } else { x = 2; }");
+        JexlScript e = JEXL.createScript("if (true) { x = 1; } else { x = 2; }");
         JexlContext jc = new MapContext();
-        Object o = e.evaluate(jc);
+        Object o = e.execute(jc);
         assertEquals("Block result is wrong", new Integer(1), o);
     }
 
     public void testBlockLastExecuted02() throws Exception {
-        JexlExpression e = JEXL.createExpression("if (false) { x = 1; } else { x = 2; }");
+        JexlScript e = JEXL.createScript("if (false) { x = 1; } else { x = 2; }");
         JexlContext jc = new MapContext();
-        Object o = e.evaluate(jc);
+        Object o = e.execute(jc);
         assertEquals("Block result is wrong", new Integer(2), o);
     }
 
     public void testNestedBlock() throws Exception {
-        JexlExpression e = JEXL.createExpression("if (true) { x = 'hello'; y = 'world';" + " if (true) { x; } y; }");
+        JexlScript e = JEXL.createScript("if (true) { x = 'hello'; y = 'world';" + " if (true) { x; } y; }");
         JexlContext jc = new MapContext();
-        Object o = e.evaluate(jc);
+        Object o = e.execute(jc);
         assertEquals("Block result is wrong", "world", o);
     }
 }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreator.java Mon Nov 25 13:35:55 2013
@@ -37,6 +37,9 @@ public class ClassCreator {
     private String sourceName = null;
     private ClassLoader loader = null;
     public static final boolean canRun = comSunToolsJavacMain();
+
+    static final String GEN_PATH = "/org/apache/commons/jexl3/generated";
+    static final String GEN_CLASS = "org.apache.commons.jexl3.generated.";
     /**
      * Check if we can invoke Sun's java compiler.
      * @return true if it is possible, false otherwise
@@ -69,17 +72,17 @@ public class ClassCreator {
         seed = s;
         className = "foo" + s;
         sourceName = className + ".java";
-        packageDir = new File(base, seed + "/org/apache/commons/jexl3/generated");
+        packageDir = new File(base, seed + GEN_PATH);
         packageDir.mkdirs();
         loader = null;
     }
 
     public String getClassName() {
-        return "org.apache.commons.jexl3.generated." + className;
+        return GEN_CLASS + className;
     }
 
     public Class<?> getClassInstance() throws Exception {
-        return getClassLoader().loadClass("org.apache.commons.jexl3.generated." + className);
+        return getClassLoader().loadClass(getClassName());
     }
 
     public ClassLoader getClassLoader() throws Exception {
@@ -128,7 +131,16 @@ public class ClassCreator {
         if (javac == null) {
             return null;
         }
-        Integer r = (Integer) jexl.invokeMethod(javac, "compile", source);
+        Integer r;
+        try {
+            r = (Integer) jexl.invokeMethod(javac, "compile", source);
+            if (r.intValue() >= 0) {
+                return getClassLoader().loadClass("org.apache.commons.jexl3.generated." + className);
+            }
+        } catch (JexlException xignore) {
+            // ignore
+        }
+        r = (Integer) jexl.invokeMethod(javac, "compile", (Object) new String[]{source});
         if (r.intValue() >= 0) {
             return getClassLoader().loadClass("org.apache.commons.jexl3.generated." + className);
         }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ClassCreatorTest.java Mon Nov 25 13:35:55 2013
@@ -24,14 +24,14 @@ import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.apache.log4j.Logger;
+import org.apache.log4j.LogManager;
 
 /**
  * Basic check on automated class creation
  */
 public class ClassCreatorTest extends JexlTestCase {
-    static final Log logger = LogFactory.getLog(JexlTestCase.class);
+    static final Logger logger = LogManager.getLogger(JexlTestCase.class);
     static final int LOOPS = 8;
     private File base = null;
     private JexlEngine jexl = null;

Added: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java?rev=1545274&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java (added)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java Mon Nov 25 13:35:55 2013
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl3;
+
+import org.apache.commons.jexl3.internal.Engine;
+/**
+ * Tests JexlContext (advanced) features.
+ */
+public class ContextNamespaceTest extends JexlTestCase {
+
+    public ContextNamespaceTest(String testName) {
+        super(testName);
+    }
+
+    /*
+     * Accesses the thread context and cast it.
+     */
+    public static class Taxes {
+        public double vat(double n) {
+            TaxesContext context = (TaxesContext) JexlEngine.getThreadContext();
+            return n * context.getVAT() / 100.;
+        }
+    }
+
+    /**
+     * A thread local context carrying a namespace and some inner constants.
+     */
+    public static class TaxesContext extends MapContext implements JexlContext.ThreadLocal, JexlContext.NamespaceResolver {
+        private final Taxes taxes = new Taxes();
+        private final double vat;
+        TaxesContext(double vat) {
+            this.vat = vat;
+        }
+        @Override
+        public Object resolveNamespace(String name) {
+           return "taxes".equals(name)? taxes : null;
+        }
+        public double getVAT() {
+            return vat;
+        }
+    }
+
+    public void testThreadedContext() throws Exception {
+        JexlEngine jexl = new Engine();
+        TaxesContext context = new TaxesContext(18.6);
+        String strs = "taxes:vat(1000)";
+        JexlScript staxes = jexl.createScript(strs);
+        Object result = staxes.execute(context);
+        assertEquals(186., result);
+    }
+
+}

Propchange: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/ContextNamespaceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/Foo.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/Foo.java?rev=1545274&r1=1545273&r2=1545274&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/Foo.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/Foo.java Mon Nov 25 13:35:55 2013
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,11 +22,11 @@ import java.util.List;
 
 /**
  * A simple bean used for testing purposes
- * 
+ *
  * @since 1.0
  */
 public class Foo {
-    
+
     private boolean beenModified = false;
     private String property1 = "some value";
     public Foo() {}
@@ -35,7 +35,7 @@ public class Foo {
             return getCheeseList().iterator();
         }
     }
-    
+
     public String bar()
     {
         return JexlTest.METHOD_STRING;
@@ -115,7 +115,7 @@ public class Foo {
     {
         return 22;
     }
-    
+
     public String getProperty1() {
         return property1;
     }