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