Author: markt
Date: Fri Dec  8 13:11:10 2017
New Revision: 1817495

URL: http://svn.apache.org/viewvc?rev=1817495&view=rev
Log:
Improve the handling of methods with varargs in EL expressions. In particular, 
the calling of a varargs method with no parameters now works correctly.
Based on a patch by Nitkalya (Ing) Wiriyanuparb.

Modified:
    tomcat/trunk/java/javax/el/Util.java
    tomcat/trunk/java/org/apache/el/util/ReflectionUtil.java
    tomcat/trunk/test/javax/el/TestBeanELResolver.java
    tomcat/trunk/test/javax/el/TesterBean.java
    tomcat/trunk/test/org/apache/el/TestMethodExpressionImpl.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/javax/el/Util.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/Util.java?rev=1817495&r1=1817494&r2=1817495&view=diff
==============================================================================
--- tomcat/trunk/java/javax/el/Util.java (original)
+++ tomcat/trunk/java/javax/el/Util.java Fri Dec  8 13:11:10 2017
@@ -38,6 +38,7 @@ import java.util.concurrent.locks.Reentr
 class Util {
 
     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
 
     /**
      * Checks whether the supplied Throwable is one that needs to be
@@ -237,11 +238,29 @@ class Util {
             }
 
             // Check the number of parameters
-            if (!(paramCount == mParamCount ||
-                    (w.isVarArgs() && paramCount >= mParamCount))) {
+            // Multiple tests to improve readability
+            if (!w.isVarArgs() && paramCount != mParamCount) {
                 // Method has wrong number of parameters
                 continue;
             }
+            if (w.isVarArgs() && paramCount < mParamCount -1) {
+                // Method has wrong number of parameters
+                continue;
+            }
+            if (w.isVarArgs() && paramCount == mParamCount && paramValues != 
null &&
+                    paramValues.length > paramCount && !paramTypes[mParamCount 
-1].isArray()) {
+                // Method arguments don't match
+                continue;
+            }
+            if (w.isVarArgs() && paramCount > mParamCount && paramValues != 
null &&
+                    paramValues.length != paramCount) {
+                // Number of parameter types and values do not agree
+                throw new IllegalArgumentException();
+            }
+            if (!w.isVarArgs() && paramValues != null && paramCount != 
paramValues.length) {
+                // Number of parameter types and values do not agree
+                throw new IllegalArgumentException();
+            }
 
             // Check the parameters match
             int exactMatch = 0;
@@ -250,9 +269,12 @@ class Util {
             boolean noMatch = false;
             for (int i = 0; i < mParamCount; i++) {
                 // Can't be null
-                if (mParamTypes[i].equals(paramTypes[i])) {
-                    exactMatch++;
-                } else if (i == (mParamCount - 1) && w.isVarArgs()) {
+                if (w.isVarArgs() && i == (mParamCount - 1)) {
+                    if (i == paramCount && paramCount == (mParamCount - 1)) {
+                        // Nothing is passed as varargs
+                        assignableMatch++;
+                        break;
+                    }
                     Class<?> varType = mParamTypes[i].getComponentType();
                     for (int j = i; j < paramCount; j++) {
                         if (isAssignableFrom(paramTypes[j], varType)) {
@@ -274,18 +296,22 @@ class Util {
                         // lead to a varArgs method matching when the result
                         // should be ambiguous
                     }
-                } else if (isAssignableFrom(paramTypes[i], mParamTypes[i])) {
-                    assignableMatch++;
                 } else {
-                    if (paramValues == null) {
-                        noMatch = true;
-                        break;
+                    if (mParamTypes[i].equals(paramTypes[i])) {
+                        exactMatch++;
+                    } else if (paramTypes[i] != null && 
isAssignableFrom(paramTypes[i], mParamTypes[i])) {
+                        assignableMatch++;
                     } else {
-                        if (isCoercibleFrom(paramValues[i], mParamTypes[i])) {
-                            coercibleMatch++;
-                        } else {
+                        if (paramValues == null) {
                             noMatch = true;
                             break;
+                        } else {
+                            if (isCoercibleFrom(paramValues[i], 
mParamTypes[i])) {
+                                coercibleMatch++;
+                            } else {
+                                noMatch = true;
+                                break;
+                            }
                         }
                     }
                 }
@@ -595,7 +621,11 @@ class Util {
         Object[] parameters = null;
         if (parameterTypes.length > 0) {
             parameters = new Object[parameterTypes.length];
-            int paramCount = params.length;
+            int paramCount;
+            if (params == null) {
+                params = EMPTY_OBJECT_ARRAY;
+            }
+            paramCount = params.length;
             if (isVarArgs) {
                 int varArgIndex = parameterTypes.length - 1;
                 // First argCount-1 parameters are standard

Modified: tomcat/trunk/java/org/apache/el/util/ReflectionUtil.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/el/util/ReflectionUtil.java?rev=1817495&r1=1817494&r2=1817495&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/el/util/ReflectionUtil.java (original)
+++ tomcat/trunk/java/org/apache/el/util/ReflectionUtil.java Fri Dec  8 
13:11:10 2017
@@ -129,6 +129,7 @@ public class ReflectionUtil {
     public static Method getMethod(EvaluationContext ctx, Object base, Object 
property,
             Class<?>[] paramTypes, Object[] paramValues)
             throws MethodNotFoundException {
+
         if (base == null || property == null) {
             throw new MethodNotFoundException(MessageFactory.get(
                     "error.method.notfound", base, property,
@@ -163,11 +164,29 @@ public class ReflectionUtil {
             }
 
             // Check the number of parameters
-            if (!(paramCount == mParamCount ||
-                    (m.isVarArgs() && paramCount >= mParamCount))) {
+            // Multiple tests to improve readability
+            if (!m.isVarArgs() && paramCount != mParamCount) {
                 // Method has wrong number of parameters
                 continue;
             }
+            if (m.isVarArgs() && paramCount < mParamCount -1) {
+                // Method has wrong number of parameters
+                continue;
+            }
+            if (m.isVarArgs() && paramCount == mParamCount && paramValues != 
null &&
+                    paramValues.length > paramCount && !paramTypes[mParamCount 
-1].isArray()) {
+                // Method arguments don't match
+                continue;
+            }
+            if (m.isVarArgs() && paramCount > mParamCount && paramValues != 
null &&
+                    paramValues.length != paramCount) {
+                // Number of parameter types and values do not agree
+                throw new IllegalArgumentException();
+            }
+            if (!m.isVarArgs() && paramValues != null && paramCount != 
paramValues.length) {
+                // Number of parameter types and values do not agree
+                throw new IllegalArgumentException();
+            }
 
             // Check the parameters match
             int exactMatch = 0;
@@ -176,15 +195,18 @@ public class ReflectionUtil {
             boolean noMatch = false;
             for (int i = 0; i < mParamCount; i++) {
                 // Can't be null
-                if (mParamTypes[i].equals(paramTypes[i])) {
-                    exactMatch++;
-                } else if (i == (mParamCount - 1) && m.isVarArgs()) {
+                if (m.isVarArgs() && i == (mParamCount - 1)) {
+                    if (i == paramCount && paramCount == (mParamCount - 1)) {
+                        // Nothing is passed as varargs
+                        assignableMatch++;
+                        break;
+                    }
                     Class<?> varType = mParamTypes[i].getComponentType();
                     for (int j = i; j < paramCount; j++) {
                         if (isAssignableFrom(paramTypes[j], varType)) {
                             assignableMatch++;
                         } else {
-                            if (paramValues == null || j >= 
paramValues.length) {
+                            if (paramValues == null) {
                                 noMatch = true;
                                 break;
                             } else {
@@ -200,18 +222,22 @@ public class ReflectionUtil {
                         // lead to a varArgs method matching when the result
                         // should be ambiguous
                     }
-                } else if (isAssignableFrom(paramTypes[i], mParamTypes[i])) {
-                    assignableMatch++;
                 } else {
-                    if (paramValues == null || i >= paramValues.length) {
-                        noMatch = true;
-                        break;
+                    if (mParamTypes[i].equals(paramTypes[i])) {
+                        exactMatch++;
+                    } else if (paramTypes[i] != null && 
isAssignableFrom(paramTypes[i], mParamTypes[i])) {
+                        assignableMatch++;
                     } else {
-                        if (isCoercibleFrom(ctx, paramValues[i], 
mParamTypes[i])) {
-                            coercibleMatch++;
-                        } else {
+                        if (paramValues == null) {
                             noMatch = true;
                             break;
+                        } else {
+                            if (isCoercibleFrom(ctx, paramValues[i], 
mParamTypes[i])) {
+                                coercibleMatch++;
+                            } else {
+                                noMatch = true;
+                                break;
+                            }
                         }
                     }
                 }
@@ -527,5 +553,4 @@ public class ReflectionUtil {
                     ;
         }
     }
-
 }

Modified: tomcat/trunk/test/javax/el/TestBeanELResolver.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/javax/el/TestBeanELResolver.java?rev=1817495&r1=1817494&r2=1817495&view=diff
==============================================================================
--- tomcat/trunk/test/javax/el/TestBeanELResolver.java (original)
+++ tomcat/trunk/test/javax/el/TestBeanELResolver.java Fri Dec  8 13:11:10 2017
@@ -18,6 +18,7 @@ package javax.el;
 
 import java.beans.FeatureDescriptor;
 import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
 import java.util.Iterator;
 
 import org.junit.Assert;
@@ -457,6 +458,486 @@ public class TestBeanELResolver {
                 new Object[] {});
     }
 
+    @Test
+    public void testInvokeVarargsCoerce01() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] {}, new String[] {});
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce02() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                null, null);
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce03() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                null, new String[] {});
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce04() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] {}, null);
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce05() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { null }, new String[] { null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce06() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                null, new String[] { null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce07() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { null }, null);
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce08() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class }, new String[] { "true" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce09() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class }, new Object[] { 
"true", null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce10() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String[].class }, new Object[] 
{ "true", null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce11() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class }, new Object[] { "10" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce12() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String[].class }, new String[] { "10" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    // Ambiguous because the Strings coerce to both Boolean and Integer hence
+    // both varargs methods match.
+    @Test(expected=MethodNotFoundException.class)
+    public void testInvokeVarargsCoerce13() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class }, new String[] { 
"10", "11" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce14() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class }, new String[] { 
"true", null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=MethodNotFoundException.class)
+    public void testInvokeVarargsCoerce15() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class }, new Object[] { 
"true", new ArrayList<>() });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    // Ambiguous because the Strings coerce to both Boolean and Integer hence
+    // both varargs methods match.
+    @Test(expected=MethodNotFoundException.class)
+    public void testInvokeVarargsCoerce16() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class, String.class },
+                new Object[] { "10", "11", "12" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargsCoerce17() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class },
+                new Object[] { "10", "11", "12" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargsCoerce18() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class, String.class, 
String.class },
+                new Object[] { "10", "11", "12" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargsCoerce19() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class, String.class, 
String.class },
+                new Object[] { "true", "10", "11", "12" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargsCoerce20() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class, String.class },
+                new Object[] { "true", "10", "11", "12" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargsCoerce21() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { String.class, String.class, String.class, 
String.class, String.class },
+                new Object[] { "true", "10", "11", "12" });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs01() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] {}, new Object[] {});
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs02() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                null, null);
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs03() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                null, new Object[] {});
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs04() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] {}, null);
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs05() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { null }, new Object[] { null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs06() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                null, new Object[] { null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs07() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { null }, null);
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs08() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class }, new Object[] { Boolean.TRUE 
});
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs09() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, Integer.class }, new Object[] 
{ Boolean.TRUE, null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs10() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, Integer[].class }, new 
Object[] { Boolean.TRUE, null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs11() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Integer.class }, new Object[] { 
Integer.valueOf(10) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs12() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Integer[].class }, new Object[] { 
Integer.valueOf(10) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs13() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Integer.class, Integer.class }, new Object[] 
{ Integer.valueOf(10), Integer.valueOf(11) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    // Note: The coercion rules are that a null of any type can be coerced to a
+    //       null of *any* other type so this works.
+    @Test
+    public void testInvokeVarargs14() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, ArrayList.class }, new 
Object[] { Boolean.TRUE, null });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=MethodNotFoundException.class)
+    public void testInvokeVarargs15() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, ArrayList.class }, new 
Object[] { Boolean.TRUE, new ArrayList<>() });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs16() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Integer.class, Integer.class, Integer.class },
+                new Object[] { Integer.valueOf(10), Integer.valueOf(11),  
Integer.valueOf(12) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargs17() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Integer.class, Integer.class },
+                new Object[] { Integer.valueOf(10), Integer.valueOf(11),  
Integer.valueOf(12) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargs18() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Integer.class, Integer.class, Integer.class, 
Integer.class },
+                new Object[] { Integer.valueOf(10), Integer.valueOf(11),  
Integer.valueOf(12) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test
+    public void testInvokeVarargs19() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, Integer.class, Integer.class, 
Integer.class },
+                new Object[] { Boolean.TRUE, Integer.valueOf(10), 
Integer.valueOf(11),  Integer.valueOf(12) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargs20() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, Integer.class, Integer.class },
+                new Object[] { Boolean.TRUE, Integer.valueOf(10), 
Integer.valueOf(11),  Integer.valueOf(12) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testInvokeVarargs21() {
+        BeanELResolver resolver = new BeanELResolver();
+        ELContext context = new 
StandardELContext(ELManager.getExpressionFactory());
+
+        Object result = resolver.invoke(context, new TesterBean(BEAN_NAME), 
"getNameVarargs",
+                new Class<?>[] { Boolean.class, Integer.class, Integer.class, 
Integer.class, Integer.class },
+                new Object[] { Boolean.TRUE, Integer.valueOf(10), 
Integer.valueOf(11),  Integer.valueOf(12) });
+
+        Assert.assertEquals(BEAN_NAME, result);
+    }
+
     private static class Bean {
 
         @SuppressWarnings("unused")

Modified: tomcat/trunk/test/javax/el/TesterBean.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/javax/el/TesterBean.java?rev=1817495&r1=1817494&r2=1817495&view=diff
==============================================================================
--- tomcat/trunk/test/javax/el/TesterBean.java (original)
+++ tomcat/trunk/test/javax/el/TesterBean.java Fri Dec  8 13:11:10 2017
@@ -29,6 +29,15 @@ public class TesterBean {
         return name;
     }
 
+    public String getNameVarargs(@SuppressWarnings("unused") Integer... 
someNumbers) {
+        return name;
+    }
+
+    public String getNameVarargs(@SuppressWarnings("unused") Boolean 
someBoolean,
+            @SuppressWarnings("unused") Integer... someNumbers) {
+        return name;
+    }
+
     public void setName(String name) {
         this.name = name;
     }

Modified: tomcat/trunk/test/org/apache/el/TestMethodExpressionImpl.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/el/TestMethodExpressionImpl.java?rev=1817495&r1=1817494&r2=1817495&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/el/TestMethodExpressionImpl.java (original)
+++ tomcat/trunk/test/org/apache/el/TestMethodExpressionImpl.java Fri Dec  8 
13:11:10 2017
@@ -20,6 +20,7 @@ package org.apache.el;
 import javax.el.ELContext;
 import javax.el.ExpressionFactory;
 import javax.el.MethodExpression;
+import javax.el.MethodNotFoundException;
 import javax.el.ValueExpression;
 
 import org.junit.Assert;
@@ -519,7 +520,8 @@ public class TestMethodExpressionImpl {
         Object r = me.invoke(context, new String[] { "aaa" });
         Assert.assertEquals("aaa", r.toString());
     }
-    @Test
+
+    @Test(expected=MethodNotFoundException.class)
     public void testBug57855e() {
         MethodExpression me = factory.createMethodExpression(context,
                 "${beanB.echo}", null , new Class[]{String.class});

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1817495&r1=1817494&r2=1817495&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Dec  8 13:11:10 2017
@@ -65,6 +65,11 @@
         that Jasper correctly parses the expression. Patch provided by Ricardo
         Martin Camarero. (markt)
       </fix>
+      <fix>
+        Improve the handling of methods with varargs in EL expressions. In
+        particular, the calling of a varargs method with no parameters now 
works
+        correctly. Based on a patch by Nitkalya (Ing) Wiriyanuparb. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to