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

Reply via email to