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);
+ }
+
+ }
}