--- test/javax/el/TestBeanELResolverVarargsInvocation.java (revision 0) +++ test/javax/el/TestBeanELResolverVarargsInvocation.java (revision 0) @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package javax.el; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.el.BeanELResolver; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TestBeanELResolverVarargsInvocation { + public static class Foo { + + public String joinDelimited(String delim, String... strings) { + StringBuilder result = new StringBuilder(); + if (strings != null) { + for (String s : strings) { + if (delim != null && result.length() > 0) { + result.append(delim); + } + result.append(s); + } + } + return result.toString(); + } + + public String join(String... strings) { + return joinDelimited(null, strings); + } + } + + private Foo foo; + private ELContext elContext; + private BeanELResolver beanELResolver; + + @Before + public void setup() { + foo = new Foo(); + beanELResolver = new BeanELResolver(); + elContext = new ELContext() { + private VariableMapper variableMapper = new VariableMapper() { + private Map vars = new HashMap(); + + @Override + public ValueExpression setVariable(String arg0, ValueExpression arg1) { + return vars.put(arg0, arg1); + } + + @Override + public ValueExpression resolveVariable(String arg0) { + return vars.get(arg0); + } + }; + private FunctionMapper functionMapper = new FunctionMapper() { + + @Override + public Method resolveFunction(String arg0, String arg1) { + return null; + } + }; + + @Override + public VariableMapper getVariableMapper() { + return variableMapper; + } + + @Override + public FunctionMapper getFunctionMapper() { + return functionMapper; + } + + @Override + public ELResolver getELResolver() { + return beanELResolver; + } + }; + } + + /** + * Tests varargs that come after an opening argument. + */ + @Test + public void testJoinDelimited() { + Assert.assertEquals(foo.joinDelimited("-", "foo", "bar", "baz"), + beanELResolver.invoke(elContext, foo, "joinDelimited", null, new Object[] { "-", "foo", "bar", "baz" })); + } + + /** + * Tests varargs that constitute a method's only parameters, as well as bogus results + * due to improper matching of ANY vararg method, and depending on the order in which + * reflected methods are encountered. + */ + @Test + public void testJoin() { + Assert.assertEquals(foo.join("foo", "bar", "baz"), + beanELResolver.invoke(elContext, foo, "join", null, new Object[] { "foo", "bar", "baz" })); + } + +} + native --- java/javax/el/BeanELResolver.java (revision 1173292) +++ java/javax/el/BeanELResolver.java (working copy) @@ -420,7 +420,8 @@ matchingMethod = getMethod(clazz, m); break; } - if (m.isVarArgs()) { + if (m.isVarArgs() && methodName.equals(m.getName()) && + paramCount > m.getParameterTypes().length - 2 ) { matchingMethod = getMethod(clazz, m); } } @@ -440,21 +441,21 @@ if (matchingMethod.isVarArgs()) { int varArgIndex = parameterTypes.length - 1; // First argCount-1 parameters are standard - for (int i = 0; (i < varArgIndex - 1); i++) { + for (int i = 0; (i < varArgIndex); i++) { parameters[i] = factory.coerceToType(params[i], parameterTypes[i]); } - // Last parameter is the varags + // Last parameter is the varargs Class varArgClass = parameterTypes[varArgIndex].getComponentType(); + final Object varargs = Array.newInstance( + varArgClass, + (paramCount - varArgIndex)); for (int i = (varArgIndex); i < paramCount; i++) { - Object varargs = Array.newInstance( - parameterTypes[paramCount], - (paramCount - varArgIndex)); - Array.set(varargs, i, + Array.set(varargs, i - varArgIndex, factory.coerceToType(params[i], varArgClass)); - parameters[varArgIndex] = varargs; } + parameters[varArgIndex] = varargs; } else { parameters = new Object[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) {