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 2012/08/10 14:36:51 UTC

svn commit: r1371687 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java test/java/org/apache/commons/jexl3/IssuesTest.java

Author: henrib
Date: Fri Aug 10 12:36:50 2012
New Revision: 1371687

URL: http://svn.apache.org/viewvc?rev=1371687&view=rev
Log:
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)

Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl3/internal/introspection/MethodKey.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java

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=1371687&r1=1371686&r2=1371687&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 Fri Aug 10 12:36:50 2012
@@ -70,7 +70,7 @@ public final class MethodKey {
      * correctly.
      * </p>
      * @param parm a may-be primitive type class
-     * @return the equivalent object class 
+     * @return the equivalent object class
      */
     static Class<?> primitiveClass(Class<?> parm) {
         // it is marginally faster to get from the map than call isPrimitive...
@@ -78,7 +78,7 @@ 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. */
@@ -530,11 +530,14 @@ public final class MethodKey {
             if (c2.length > c1.length) {
                 return LESS_SPECIFIC;
             }
+            // same length, keep ultimate param offset for vararg checks
+            final int length = c1.length;
+            final int ultimate = c1.length - 1;
 
             // ok, move on and compare those of equal lengths
-            for (int i = 0; i < c1.length; ++i) {
+            for (int i = 0; i < length; ++i) {
                 if (c1[i] != c2[i]) {
-                    boolean last = (i == c1.length - 1);
+                    boolean last = (i == ultimate);
                     c1MoreSpecific = c1MoreSpecific || isStrictConvertible(c2[i], c1[i], last);
                     c2MoreSpecific = c2MoreSpecific || isStrictConvertible(c1[i], c2[i], last);
                 }
@@ -553,11 +556,12 @@ public final class MethodKey {
 
             // attempt to choose by picking the one with the greater number of primitives or latest primitive parameter
             int primDiff = 0;
-            for (int c = 0; c < c1.length; ++c) {
-                if (c1[c].isPrimitive()) {
+            for (int c = 0; c < length; ++c) {
+                boolean last = (c == ultimate);
+                if (isPrimitive(c1[c], last)) {
                     primDiff += 1 << c;
                 }
-                if (c2[c].isPrimitive()) {
+                if (isPrimitive(c2[c], last)) {
                     primDiff -= 1 << c;
                 }
             }
@@ -574,6 +578,24 @@ 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)
+         * @return true if primitive, false otherwise
+         */
+        private boolean isPrimitive(Class<?> c,  boolean possibleVarArg) {
+            if (c != null) {
+                if (c.isPrimitive()) {
+                    return true;
+                } else if (possibleVarArg) {
+                    Class<?> t = c.getComponentType();
+                    return t != null && t.isPrimitive();
+                }
+            }
+            return false;
+        }
+
+        /**
          * Returns all methods that are applicable to actual argument types.
          *
          * @param methods list of all candidate methods
@@ -661,8 +683,7 @@ public final class MethodKey {
          *                       in the method declaration
          * @return see isMethodInvocationConvertible.
          */
-        private boolean isConvertible(Class<?> formal, Class<?> actual,
-                boolean possibleVarArg) {
+        private boolean isConvertible(Class<?> formal, Class<?> actual, boolean possibleVarArg) {
             // if we see Void.class, the argument was null
             return isInvocationConvertible(formal, actual.equals(Void.class) ? null : actual, possibleVarArg);
         }
@@ -676,8 +697,7 @@ 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);
         }

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java?rev=1371687&r1=1371686&r2=1371687&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl3/IssuesTest.java Fri Aug 10 12:36:50 2012
@@ -40,7 +40,6 @@ public class IssuesTest extends JexlTest
         java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
     }
 
-
     // JEXL-49: blocks not parsed (fixed)
     public void test49() throws Exception {
         JexlEngine jexl = new Engine();
@@ -197,11 +196,11 @@ public class IssuesTest extends JexlTest
         ctxt.set("a", null);
 
         String[] exprs = {
-            //"10 + null",
-            //"a - 10",
-            //"b * 10",
-            "a % b"//,
-        //"1000 / a"
+            "10 + null",
+            "a - 10",
+            "b * 10",
+            "a % b",
+            "1000 / a"
         };
         for (int e = 0; e < exprs.length; ++e) {
             try {
@@ -814,16 +813,16 @@ public class IssuesTest extends JexlTest
         JexlEngine jexl = new JexlBuilder().arithmetic(new Arithmetic132()).namespaces(ns).create();
 
         Object evaluate = jexl.createExpression("1/0").evaluate(null);
-        assertTrue(Double.isInfinite((Double)evaluate));
+        assertTrue(Double.isInfinite((Double) evaluate));
 
         evaluate = jexl.createExpression("-1/0").evaluate(null);
-        assertTrue(Double.isInfinite((Double)evaluate));
+        assertTrue(Double.isInfinite((Double) evaluate));
 
         evaluate = jexl.createExpression("1.0/0.0").evaluate(null);
-        assertTrue(Double.isInfinite((Double)evaluate));
+        assertTrue(Double.isInfinite((Double) evaluate));
 
         evaluate = jexl.createExpression("-1.0/0.0").evaluate(null);
-        assertTrue(Double.isInfinite((Double)evaluate));
+        assertTrue(Double.isInfinite((Double) evaluate));
 
         evaluate = jexl.createExpression("math:abs(-42)").evaluate(null);
         assertEquals(42, evaluate);
@@ -875,7 +874,6 @@ public class IssuesTest extends JexlTest
         assertEquals(42, result);
     }
 
-
     @Test
     public void test136() throws Exception {
         JexlEngine jexl = new Engine();
@@ -894,4 +892,42 @@ public class IssuesTest extends JexlTest
         result = expr.evaluate(jc);
         assertEquals("EXPR01 result", 22, result);
     }
+
+    public static class Context137 extends MapContext implements JexlContext.NamespaceResolver {
+        public static void log(Object fmt, Object... arr) {
+
+            System.out.println(String.format(fmt.toString(), arr));
+        }
+
+        public static void log(Object fmt, int... arr) {
+            System.out.println(String.format(fmt.toString(), arr));
+        }
+
+        @Override
+        public Object resolveNamespace(String name) {
+            return this;
+        }
+    }
+
+    @Test
+    public void test137() throws Exception {
+        String[] SCRIPTS = {
+            "var x = null; log('x = %s', x);",
+            "var x = 'abc'; log('x = %s', x);",
+            "var x = 333; log('x = %s', x);",
+            "var x = [1, 2]; log('x = %s', x);",
+            "var x = ['a', 'b']; log('x = %s', x);",
+            "var x = {1:'A', 2:'B'}; log('x = %s', x);"
+        };
+        JexlEngine jexl = new JexlBuilder().create();
+        JexlContext jc = new Context137();
+        JexlScript script;
+
+        for (String stext : SCRIPTS) {
+            System.out.println(stext);
+            script = jexl.createScript(stext);
+            script.execute(jc);
+        }
+
+    }
 }