You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ra...@apache.org on 2009/07/18 21:26:03 UTC

svn commit: r795421 [2/2] - in /commons/proper/jexl/branches/2.0: ./ src/java/org/apache/commons/jexl/ src/java/org/apache/commons/jexl/util/ src/java/org/apache/commons/jexl/util/introspection/ src/test/org/apache/commons/jexl/

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/ClassMap.java Sat Jul 18 19:26:02 2009
@@ -24,7 +24,7 @@
 import org.apache.commons.logging.Log;
 
 /**
- * Taken from the Velocity tree so we can be self-sufficient
+ * Taken from the Velocity tree so we can be self-sufficient.
  *
  * A cache of introspection information for a specific class instance.
  * Keys objects by an agregation of the method name and the names of classes
@@ -39,13 +39,6 @@
  * @since 1.0
  */
 public class ClassMap {
-
-    /**
-     * Class passed into the constructor used to as the basis for the Method map.
-     */
-    private final Class<?> clazz;
-    /** logger. */
-    private final Log rlog;
     /** cache of methods. */
     private final MethodCache methodCache;
 
@@ -56,18 +49,15 @@
      * @param log the logger.
      */
     public ClassMap(Class<?> aClass, Log log) {
-        clazz = aClass;
-        this.rlog = log;
-        methodCache = new MethodCache();
-
-        populateMethodCache();
+        methodCache = createMethodCache(aClass, log);
     }
 
     /**
-     * @return the class object whose methods are cached by this map.
+     * Gets the methods names cached by this map.
+     * @return the array of method names
      */
-    Class<?> getCachedClass() {
-        return clazz;
+    String[] getMethodNames() {
+        return methodCache.names();
     }
 
     /**
@@ -84,11 +74,13 @@
     }
 
     /**
-     * Populate the Map of direct hits. These
-     * are taken from all the public methods
+     * Populate the Map of direct hits. These are taken from all the public methods
      * that our class, its parents and their implemented interfaces provide.
+     * @param classToReflect the class to cache
+     * @param log the Log
+     * @return a newly allocated & filled up cache
      */
-    private void populateMethodCache() {
+    private static MethodCache createMethodCache(Class<?> classToReflect, Log log) {
         //
         // Build a list of all elements in the class hierarchy. This one is bottom-first (i.e. we start
         // with the actual declaring class and its interfaces and then move up (superclass etc.) until we
@@ -103,42 +95,54 @@
         // hit the public elements sooner or later because we reflect all the public elements anyway.
         //
         // Ah, the miracles of Java for(;;) ...
-        for (Class<?> classToReflect = getCachedClass(); classToReflect != null; classToReflect = classToReflect.getSuperclass()) {
+        MethodCache cache = new MethodCache();
+        for (;classToReflect != null; classToReflect = classToReflect.getSuperclass()) {
             if (Modifier.isPublic(classToReflect.getModifiers())) {
-                populateMethodCacheWith(methodCache, classToReflect);
+                populateMethodCacheWith(cache, classToReflect, log);
             }
             Class<?>[] interfaces = classToReflect.getInterfaces();
             for (int i = 0; i < interfaces.length; i++) {
-                populateMethodCacheWithInterface(methodCache, interfaces[i]);
+                populateMethodCacheWithInterface(cache, interfaces[i], log);
             }
         }
+        return cache;
     }
 
-    /* recurses up interface hierarchy to get all super interfaces */
-    private void populateMethodCacheWithInterface(MethodCache methodCache, Class<?> iface) {
+    /**
+     * Recurses up interface hierarchy to get all super interfaces.
+     * @param cache the cache to fill
+     * @param iface the interface to populate the cache from
+     * @param log the Log
+     */
+    private static void populateMethodCacheWithInterface(MethodCache cache, Class<?> iface, Log log) {
         if (Modifier.isPublic(iface.getModifiers())) {
-            populateMethodCacheWith(methodCache, iface);
+            populateMethodCacheWith(cache, iface, log);
         }
         Class<?>[] supers = iface.getInterfaces();
         for (int i = 0; i < supers.length; i++) {
-            populateMethodCacheWithInterface(methodCache, supers[i]);
+            populateMethodCacheWithInterface(cache, supers[i], log);
         }
     }
 
-    private void populateMethodCacheWith(MethodCache methodCache, Class<?> classToReflect) {
+    /**
+     * Recurses up class hierarchy to get all super classes.
+     * @param cache the cache to fill
+     * @param clazz the class to populate the cache from
+     * @param log the Log
+     */
+    private static void populateMethodCacheWith(MethodCache cache, Class<?> clazz, Log log) {
         try {
-            Method[] methods = classToReflect.getDeclaredMethods();
+            Method[] methods = clazz.getDeclaredMethods();
             for (int i = 0; i < methods.length; i++) {
                 int modifiers = methods[i].getModifiers();
                 if (Modifier.isPublic(modifiers)) {
-                    methodCache.put(methods[i]);
+                    cache.put(methods[i]);
                 }
             }
-        }
-        catch (SecurityException se) // Everybody feels better with...
-        {
-            if (rlog.isDebugEnabled()) {
-                rlog.debug("While accessing methods of " + classToReflect + ": ", se);
+        } catch (SecurityException se) {
+            // Everybody feels better with...
+            if (log.isDebugEnabled()) {
+                log.debug("While accessing methods of " + clazz + ": ", se);
             }
         }
     }
@@ -150,8 +154,8 @@
      * @version $Id$
      * <p>
      * It stores the association between:
-     *  a key made of a method name & an array of argument types. (@see MethodCache.MethodKey)
-     *  a method.
+     *  - a key made of a method name & an array of argument types. (@see MethodCache.MethodKey)
+     *  - a method.
      * </p>
      * <p>
      * Since the invocation of the associated method is dynamic, there is no need (nor way) to differentiate between
@@ -161,31 +165,35 @@
      * @version $Id$
      */
     static class MethodCache {
-
         /**
          * A method that returns itself used as a marker for cache miss,
          * allows the underlying cache map to be strongly typed.
+         * @return itself as a method
          */
-        public static Method CacheMiss() {
+        public static Method cacheMiss() {
             try {
-                return MethodCache.class.getMethod("CacheMiss");
+                return MethodCache.class.getMethod("cacheMiss");
             } // this really cant make an error...
             catch (Exception xio) {
             }
             return null;
         }
-        private static final Method CACHE_MISS = CacheMiss();
-        private static final Map<Class<?>, Class<?>> convertPrimitives;
+        /** The cache miss marker method. */
+        private static final Method CACHE_MISS = cacheMiss();
+        /** The initial size of the primitive conversion map. */
+        private static final int PRIMITIVE_SIZE = 13;
+        /** The primitive type to class conversion map. */
+        private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPES;
         static {
-            convertPrimitives = new HashMap<Class<?>, Class<?>>(13);
-            convertPrimitives.put(Boolean.TYPE, Boolean.class);
-            convertPrimitives.put(Byte.TYPE, Byte.class);
-            convertPrimitives.put(Character.TYPE, Character.class);
-            convertPrimitives.put(Double.TYPE, Double.class);
-            convertPrimitives.put(Float.TYPE, Float.class);
-            convertPrimitives.put(Integer.TYPE, Integer.class);
-            convertPrimitives.put(Long.TYPE, Long.class);
-            convertPrimitives.put(Short.TYPE, Short.class);
+            PRIMITIVE_TYPES = new HashMap<Class<?>, Class<?>>(PRIMITIVE_SIZE);
+            PRIMITIVE_TYPES.put(Boolean.TYPE, Boolean.class);
+            PRIMITIVE_TYPES.put(Byte.TYPE, Byte.class);
+            PRIMITIVE_TYPES.put(Character.TYPE, Character.class);
+            PRIMITIVE_TYPES.put(Double.TYPE, Double.class);
+            PRIMITIVE_TYPES.put(Float.TYPE, Float.class);
+            PRIMITIVE_TYPES.put(Integer.TYPE, Integer.class);
+            PRIMITIVE_TYPES.put(Long.TYPE, Long.class);
+            PRIMITIVE_TYPES.put(Short.TYPE, Short.class);
         }
 
         /** Converts a primitive type to its corresponding class.
@@ -199,7 +207,7 @@
         static final Class<?> primitiveClass(Class<?> parm) {
             // it is marginally faster to get from the map than call isPrimitive...
             //if (!parm.isPrimitive()) return parm;
-            Class<?> prim = convertPrimitives.get(parm);
+            Class<?> prim = PRIMITIVE_TYPES.get(parm);
             return prim == null ? parm : prim;
         }
         /**
@@ -229,12 +237,18 @@
          * @return A Method object representing the method to invoke or null.
          * @throws MethodMap.AmbiguousException When more than one method is a match for the parameters.
          */
-        public Method get(final String name, final Object[] params)
+        Method get(final String name, final Object[] params)
                 throws MethodMap.AmbiguousException {
             return get(new MethodKey(name, params));
         }
 
-        public Method get(final MethodKey methodKey)
+        /**
+         * Finds a Method using a MethodKey.
+         * @param methodKey the method key
+         * @return a method
+         * @throws org.apache.commons.jexl.util.introspection.MethodMap.AmbiguousException
+         */
+        Method get(final MethodKey methodKey)
                 throws MethodMap.AmbiguousException {
             synchronized (methodMap) {
                 Method cacheEntry = cache.get(methodKey);
@@ -264,7 +278,11 @@
             }
         }
 
-        public void put(Method method) {
+        /**
+         * Adds a method to the map.
+         * @param method the method to add
+         */
+        void put(Method method) {
             synchronized (methodMap) {
                 MethodKey methodKey = new MethodKey(method);
                 // We don't overwrite methods. Especially not if we fill the
@@ -277,27 +295,45 @@
                 }
             }
         }
+
+        /**
+         * Gets all the method names from this map.
+         * @return the array of method name
+         */
+        String[] names() {
+            synchronized (methodMap) {
+                return methodMap.names();
+            }
+        }
     }
 
     /**
-     * A method key for the introspector cache:
-     * This replaces the original key scheme which used to build the key by concatenating the method name and parameters
-     * class names as one string with the exception that primitive types were converted to their object class equivalents.
+     * A method key for the introspector cache.
+     * <p>
+     * This replaces the original key scheme which used to build the key
+     * by concatenating the method name and parameters class names as one string
+     * with the exception that primitive types were converted to their object class equivalents.
+     * </p>
+     * <p>
      * The key is still based on the same information, it is just wrapped in an object instead.
-     * Primitive type classes are converted to they object equivalent to make a key; int foo(int) and int foo(Integer) do
-     * generate the same key.
-     * A key can be constructed either from arguments (array of objects) or from parameters (array of class).
+     * Primitive type classes are converted to they object equivalent to make a key;
+     * int foo(int) and int foo(Integer) do generate the same key.
+     * </p>
+     * A key can be constructed either from arguments (array of objects) or from parameters
+     * (array of class).
      * Roughly 3x faster than string key to access the map & uses less memory.
      */
     static class MethodKey {
-        /** The hash code */
-        final int hashCode;
+        /** The hash code. */
+        private final int hashCode;
         /** The method name. */
         final String method;
         /** The parameters. */
         final Class<?>[] params;
         /** A marker for empty parameter list. */
-        static final Class<?>[] NOARGS = new Class<?>[0];
+        private static final Class<?>[] NOARGS = new Class<?>[0];
+        /** The hash code constants. */
+        private static final int HASH = 37;
 
         /** Builds a MethodKey from a method.
          *  Used to store information in the method map.
@@ -306,12 +342,14 @@
             this(method.getName(), method.getParameterTypes());
         }
 
-        /** Builds a MethodKey from a method name and a set of arguments (objects).
+        /** Creates a MethodKey from a method name and a set of arguments (objects).
          *  Used to query the method map.
+         * @param method the method name
+         * @param args the arguments instances to match the method signature
          */
-        MethodKey(String method, Object[] args) {
+        MethodKey(String aMethod, Object[] args) {
             // !! keep this in sync with the other ctor (hash code) !!
-            this.method = method;
+            this.method = aMethod;
             int hash = this.method.hashCode();
             final int size;
             if (args != null && (size = args.length) > 0) {
@@ -322,7 +360,7 @@
                     // no need to go thru primitive type conversion since these are objects
                     Class<?> parm = arg == null ? Object.class : arg.getClass();
                     // }
-                    hash = (37 * hash) + parm.hashCode();
+                    hash = (HASH * hash) + parm.hashCode();
                     this.params[p] = parm;
                 }
             } else {
@@ -331,12 +369,14 @@
             this.hashCode = hash;
         }
 
-        /** Builds a MethodKey from a method name and a set of parameters (classes).
+        /** Creates a MethodKey from a method name and a set of parameters (classes).
          *  Used to store information in the method map. ( @see MethodKey#primitiveClass )
+         * @param method the method name
+         * @param args the argument classes to match the method signature
          */
-        MethodKey(String method, Class<?>[] args) {
+        MethodKey(String aMethod, Class<?>[] args) {
             // !! keep this in sync with the other ctor (hash code) !!
-            this.method = method;
+            this.method = aMethod;
             int hash = this.method.hashCode();
             final int size;
             if (args != null && (size = args.length) > 0) {
@@ -345,7 +385,7 @@
                     // ctor(Class): {
                     Class<?> parm = MethodCache.primitiveClass(args[p]);
                     // }
-                    hash = (37 * hash) + parm.hashCode();
+                    hash = (HASH * hash) + parm.hashCode();
                     this.params[p] = parm;
                 }
             } else {

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Introspector.java Sat Jul 18 19:26:02 2009
@@ -100,7 +100,8 @@
             /*
              *  whoops.  Ambiguous.  Make a nice log message and return null...
              */
-            StringBuilder msg = new StringBuilder("Introspection Error : Ambiguous method invocation ").append(name).append("( ");
+            StringBuilder msg = new StringBuilder("Introspection Error : Ambiguous method invocation ");
+            msg.append(name).append("( ");
             for (int i = 0; i < params.length; i++) {
                 if (i > 0) {
                     msg.append(", ");

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/IntrospectorBase.java Sat Jul 18 19:26:02 2009
@@ -101,10 +101,32 @@
             throw new IllegalArgumentException("params object is null!");
         }
 
-        ClassMap classMap;
+        ClassMap classMap = getMap(c);
 
+        return classMap.findMethod(name, params);
+    } // CSON: RedundantThrows
+
+    /**
+     * Gets the accessible methods names known for a given class.
+     * @param c the class
+     * @return the class method names
+     */
+    public String[] getMethodNames(Class<?> c) {
+        if (c == null) {
+            return new String[0];
+        }
+        ClassMap classMap = getMap(c);
+        return classMap.getMethodNames();
+
+    }
+
+    /**
+     * Gets the ClassMap for a given class.
+     * @return the class map
+     */
+    private ClassMap getMap(Class<?> c) {
         synchronized (classMethodMaps) {
-            classMap = classMethodMaps.get(c);
+            ClassMap classMap = classMethodMaps.get(c);
             /*
              * if we don't have this, check to see if we have it by name. if so,
              * then we have a classloader change so dump our caches.
@@ -122,11 +144,9 @@
 
                 classMap = createClassMap(c);
             }
+            return classMap;
         }
-
-        return classMap.findMethod(name, params);
-    } // CSON: RedundantThrows
-
+    }
 
     /**
      * Creates a class map for specific class and registers it in the cache.

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/MethodMap.java Sat Jul 18 19:26:02 2009
@@ -85,6 +85,15 @@
     }
 
     /**
+     * Returns the array of method names accessible in this class.
+     * @return the array of names
+     */
+    public synchronized String[] names() {
+        java.util.Set<String> set = methodByNameMap.keySet();
+        return set.toArray(new String[set.size()]);
+    }
+
+    /**
      * <p>
      * Find a method.  Attempts to find the
      * most specific applicable method using the
@@ -113,11 +122,16 @@
      *                            specific applicable method
      */
     // CSOFF: RedundantThrows
-    public Method find(String methodName, Object[] args)
-            throws AmbiguousException {
+    public Method find(String methodName, Object[] args) throws AmbiguousException {
         return find(new ClassMap.MethodKey(methodName, args));
     }
 
+    /**
+     * Finds a method by key.
+     * @param methodKey the key
+     * @return the method
+     * @throws AmbiguousException if find is ambiguous
+     */
     Method find(ClassMap.MethodKey methodKey) throws AmbiguousException {
         List<Method> methodList = get(methodKey.method);
         if (methodList == null) {

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/Uberspect.java Sat Jul 18 19:26:02 2009
@@ -33,7 +33,9 @@
      */
     void init();
 
-    /** Returns the underlying introspector. */
+    /** Gets underlying introspector.
+     * @return the introspector
+     */
     public Introspector getIntrospector();
     
     /**

Modified: commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java (original)
+++ commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/introspection/UberspectImpl.java Sat Jul 18 19:26:02 2009
@@ -46,23 +46,23 @@
  */
 public class UberspectImpl implements Uberspect, UberspectLoggable {
     /**
-     * index of the first character of the property.
+     * Index of the first character of the property.
      */
     private static final int PROPERTY_START_INDEX = 3;
-    /*
-     * static signature for method(object,object)
+    /**
+     * Static signature for method(object,object).
      */
     static final Class<?>[] OBJECT_OBJECT = { Object.class, Object.class };
     /**
      * Our runtime logger.
      */
     private Log rlog;
-
     /**
-     * the default Velocity introspector.
+     * The default Velocity introspector.
      */
     private Introspector introspector;
-
+    
+    /** {@inheritDoc} */
     public Introspector getIntrospector() {
         return introspector;
     }
@@ -95,13 +95,15 @@
         } else if (obj instanceof Map<?,?>) {
             return ((Map<?,?>) obj).values().iterator();
         } else if (obj instanceof Iterator<?>) {
-                rlog.warn("Warning! The iterative " + " is an Iterator in the #foreach() loop at [" + i.getLine() + ","
+                rlog.warn("Warning! The iterative "
+                    + " is an Iterator in the #foreach() loop at [" + i.getLine() + ","
                     + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
                     + " if used in more than once, this may lead to" + " unexpected results.");
 
             return ((Iterator<?>) obj);
         } else if (obj instanceof Enumeration<?>) {
-                rlog.warn("Warning! The iterative " + " is an Enumeration in the #foreach() loop at [" + i.getLine() + ","
+                rlog.warn("Warning! The iterative "
+                    + " is an Enumeration in the #foreach() loop at [" + i.getLine() + ","
                     + i.getColumn() + "]" + " in template " + i.getTemplateName() + ". Because it's not resetable,"
                     + " if used in more than once, this may lead to" + " unexpected results.");
 
@@ -409,7 +411,10 @@
         }
     } // CSON: VisibilityModifier
 
-    
+
+    /**
+     * Concrete instance of VelPropertyGet.
+     */
     public static class VelGetterImpl implements VelPropertyGet {
         /**
          * executor for performing the get.
@@ -455,7 +460,9 @@
         }
     }
 
-    
+    /**
+     * Concrete instance of VelPropertySet.
+     */
     public static class VelSetterImpl implements VelPropertySet {
         /**
          * the method to call.

Modified: commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/IssuesTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/IssuesTest.java?rev=795421&r1=795420&r2=795421&view=diff
==============================================================================
--- commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/IssuesTest.java (original)
+++ commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/IssuesTest.java Sat Jul 18 19:26:02 2009
@@ -139,21 +139,21 @@
         assertTrue("should be true", (Boolean) value);
     }
 
-    // JEXL-52: can be implemented by deriving Interpreter.{g,s}etAttribute; wontfix
-    // JEXL-50: can be implemented through a namespace:function or through JexlArithmetic derivation - wontfix
-
-    // JEXL-46: regexp syntax; should we really add more syntactic elements? - later/vote?
-    // JEXL-45: unhandled division by zero; already fixed in trunk
-
-    // JEXL-35: final API requirements; fixed in trunk ?
-    // JEXL-32: BigDecimal values are treated as Long values which results in loss of precision; no longer affects 2.0 // Dion
-    // JEXL-21: operator overloading / hooks on operator processing (wontfix, derive JexlArithmetic)
-    // JEXL-20: checkstyle
-    // JEXL-3: static method resolution; fixed in trunk
-    // JEXL-3: change to JexlContext (setVar, getVar) - later, watch out for JEXL-10, differentiate null versus undefined?
+    // JEXL-52: can be implemented by deriving Interpreter.{g,s}etAttribute; later
+    public void test52base() throws Exception {
+        JexlEngine jexl = new JexlEngine();
+        // most likely, call will be in an Interpreter, getUberspect
+        String[] names = jexl.uberspect.getIntrospector().getMethodNames(Another.class);
+        assertTrue("should find methods", names.length > 0);
+        int found = 0;
+        for(String name : names) {
+            if ("foo".equals(name) || "goo".equals(name))
+                found += 1;
+        }
+        assertTrue("should have foo & goo", found == 2);
+    }
 
-    // JEXL-10: Make possible checking for unresolved variables
-    // JEXL-11: Don't make null convertible into anything
+    // JEXL-10/JEXL-11: variable checking, null operand is error
     public void test11() throws Exception {
         JexlEngine jexl = new JexlEngine();
         // ensure errors will throw
@@ -183,7 +183,7 @@
         }
     }
     public static void main(String[] args) throws Exception {
-        new IssuesTest().test11();
+        new IssuesTest().test52base();
     }
 
 }
\ No newline at end of file