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: [email protected]
For additional commands, e-mail: [email protected]