Author: markt Date: Sat Mar 24 21:33:47 2012 New Revision: 1304933 URL: http://svn.apache.org/viewvc?rev=1304933&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=52970 Take account of coercion rules when invoking methods
Added: tomcat/tc7.0.x/trunk/test/org/apache/el/TesterBeanEnum.java - copied unchanged from r1304930, tomcat/trunk/test/org/apache/el/TesterBeanEnum.java Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/el/parser/AstValue.java tomcat/tc7.0.x/trunk/java/org/apache/el/util/ReflectionUtil.java tomcat/tc7.0.x/trunk/test/org/apache/el/TestMethodExpressionImpl.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1304930-1304932 Modified: tomcat/tc7.0.x/trunk/java/org/apache/el/parser/AstValue.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/el/parser/AstValue.java?rev=1304933&r1=1304932&r2=1304933&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/el/parser/AstValue.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/el/parser/AstValue.java Sat Mar 24 21:33:47 2012 @@ -230,7 +230,8 @@ public final class AstValue extends Simp @SuppressWarnings("rawtypes") Class[] paramTypes) throws ELException { Target t = getTarget(ctx); - Method m = ReflectionUtil.getMethod(t.base, t.property, paramTypes); + Method m = ReflectionUtil.getMethod( + t.base, t.property, paramTypes, null); return new MethodInfo(m.getName(), m.getReturnType(), m .getParameterTypes()); } @@ -244,19 +245,20 @@ public final class AstValue extends Simp Target t = getTarget(ctx); Method m = null; Object[] values = null; + Class<?>[] types = null; if (isParametersProvided()) { values = ((AstMethodParameters) this.jjtGetChild( this.jjtGetNumChildren() - 1)).getParameters(ctx); - Class<?>[] types = getTypesFromValues(values); - m = ReflectionUtil.getMethod(t.base, t.property, types); + types = getTypesFromValues(values); } else { - m = ReflectionUtil.getMethod(t.base, t.property, paramTypes); values = paramValues; + types = paramTypes; } - if (m.isVarArgs()) { - // May need to convert values - values = toVarArgs(values, m); - } + m = ReflectionUtil.getMethod(t.base, t.property, types, values); + + // Handle varArgs and any co-ercion required + values = convertArgs(values, m); + Object result = null; try { result = m.invoke(t.base, values); @@ -277,17 +279,34 @@ public final class AstValue extends Simp return result; } - private Object[] toVarArgs(Object[] src, Method m) { - int paramCount = m.getParameterTypes().length; + private Object[] convertArgs(Object[] src, Method m) { + Class<?>[] types = m.getParameterTypes(); + if (types.length == 0) { + return new Object[0]; + } + int paramCount = types.length; + Object[] dest = new Object[paramCount]; - Object[] varArgs = (Object[]) Array.newInstance( - m.getParameterTypes()[paramCount - 1].getComponentType(), - src.length - (paramCount - 1)); - System.arraycopy(src, 0, dest, 0, paramCount - 1); - System.arraycopy(src, paramCount - 1, varArgs, 0, - src.length - (paramCount - 1)); - dest[paramCount - 1] = varArgs; + + for (int i = 0; i < paramCount - 1; i++) { + dest[i] = ELSupport.coerceToType(src[i], types[i]); + } + + if (m.isVarArgs()) { + Object[] varArgs = (Object[]) Array.newInstance( + m.getParameterTypes()[paramCount - 1].getComponentType(), + src.length - (paramCount - 1)); + for (int i = 0; i < src.length - (paramCount - 1); i ++) { + varArgs[i] = ELSupport.coerceToType(src[paramCount - 1 + i], + types[paramCount - 1].getComponentType()); + } + dest[paramCount - 1] = varArgs; + } else { + dest[paramCount - 1] = ELSupport.coerceToType( + src[paramCount - 1], types[paramCount - 1]); + } + return dest; } Modified: tomcat/tc7.0.x/trunk/java/org/apache/el/util/ReflectionUtil.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/el/util/ReflectionUtil.java?rev=1304933&r1=1304932&r2=1304933&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/el/util/ReflectionUtil.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/el/util/ReflectionUtil.java Sat Mar 24 21:33:47 2012 @@ -23,8 +23,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import javax.el.ELException; import javax.el.MethodNotFoundException; +import org.apache.el.lang.ELSupport; + /** * Utilities for Managing Serialization and Reflection @@ -106,12 +109,14 @@ public class ReflectionUtil { * @param base the object that owns the method * @param property the name of the method * @param paramTypes the parameter types to use + * @param paramValues the parameter values * @return the method specified * @throws MethodNotFoundException */ @SuppressWarnings("null") public static Method getMethod(Object base, Object property, - Class<?>[] paramTypes) throws MethodNotFoundException { + Class<?>[] paramTypes, Object[] paramValues) + throws MethodNotFoundException { if (base == null || property == null) { throw new MethodNotFoundException(MessageFactory.get( "error.method.notfound", base, property, @@ -163,15 +168,30 @@ public class ReflectionUtil { Class<?> varType = mParamTypes[i].getComponentType(); for (int j = i; j < paramCount; j++) { if (!isAssignableFrom(paramTypes[j], varType)) { - break; + if (paramValues == null) { + noMatch = true; + break; + } else { + if (!isCoercibleFrom(paramValues[j], varType)) { + noMatch = true; + break; + } + } } // Don't treat a varArgs match as an exact match, it can // lead to a varArgs method matching when the result // should be ambiguous } } else if (!isAssignableFrom(paramTypes[i], mParamTypes[i])) { - noMatch = true; - break; + if (paramValues == null) { + noMatch = true; + break; + } else { + if (!isCoercibleFrom(paramValues[i], mParamTypes[i])) { + noMatch = true; + break; + } + } } } if (noMatch) { @@ -299,6 +319,17 @@ public class ReflectionUtil { return targetClass.isAssignableFrom(src); } + private static boolean isCoercibleFrom(Object src, Class<?> target) { + // TODO: This isn't pretty but it works. Significant refactoring would + // be required to avoid the exception. + try { + ELSupport.coerceToType(src, target); + } catch (ELException e) { + return false; + } + return true; + } + protected static final String paramString(Class<?>[] types) { if (types != null) { StringBuilder sb = new StringBuilder(); Modified: tomcat/tc7.0.x/trunk/test/org/apache/el/TestMethodExpressionImpl.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/el/TestMethodExpressionImpl.java?rev=1304933&r1=1304932&r2=1304933&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/test/org/apache/el/TestMethodExpressionImpl.java (original) +++ tomcat/tc7.0.x/trunk/test/org/apache/el/TestMethodExpressionImpl.java Sat Mar 24 21:33:47 2012 @@ -75,6 +75,10 @@ public class TestMethodExpressionImpl { TesterBeanC beanC = new TesterBeanC(); context.getVariableMapper().setVariable("beanC", factory.createValueExpression(beanC, TesterBeanC.class)); + + TesterBeanEnum beanEnum = new TesterBeanEnum(); + context.getVariableMapper().setVariable("beanEnum", + factory.createValueExpression(beanEnum, TesterBeanEnum.class)); } @Test @@ -120,7 +124,7 @@ public class TestMethodExpressionImpl { me3.invoke(context, new Object[] { "JUnit2" })); assertEquals("Hello JUnit from B", me2.invoke(context, new Object[] { null })); - assertEquals("Hello null from B", + assertEquals("Hello from B", me3.invoke(context, new Object[] { null })); } @@ -413,4 +417,17 @@ public class TestMethodExpressionImpl { assertEquals("Hello from BB", actual); } + @Test + public void testBug52970() { + MethodExpression me = factory.createMethodExpression(context, + "${beanEnum.submit('APPLE')}", null , + new Class<?>[] { TesterBeanEnum.class }); + me.invoke(context, null); + + ValueExpression ve = factory.createValueExpression(context, + "#{beanEnum.lastSubmitted}", TesterEnum.class); + TesterEnum actual = (TesterEnum) ve.getValue(context); + assertEquals(TesterEnum.APPLE, actual); + + } } Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1304933&r1=1304932&r2=1304933&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Sat Mar 24 21:33:47 2012 @@ -181,6 +181,10 @@ <bug>52776</bug>: Refactor the code so JspFragment.invoke cleans up after itself. Patch provided by Karl von Randow. (markt) </fix> + <fix> + <bug>52970</bug>: Take account of coercion rules when invoking methods + via EL. (markt) + </fix> </changelog> </subsection> <subsection name="Cluster"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org