Included below are two test cases which fail. The first calls an overloaded method on an object. The second calls an overloaded constructor. More details below. 1.) Here's the first test. @Test public void test01() { ELProcessor processor = new ELProcessor(); processor.defineBean("sb", new StringBuilder()); Assert.assertEquals("a", processor.eval("sb.append('a'); sb.toString()")); } This fails with the following stack trace. javax.el.ELException: Cannot convert a of type class java.lang.String to long at org.apache.el.lang.ELSupport.coerceToNumber(ELSupport.java:349) at org.apache.el.lang.ELSupport.coerceToNumber(ELSupport.java:328) at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:450) at org.apache.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:48) at javax.el.Util.buildParameters(Util.java:351) at javax.el.BeanELResolver.invoke(BeanELResolver.java:173) at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:84) at org.apache.el.parser.AstValue.getValue(AstValue.java:157) at org.apache.el.parser.AstSemicolon.getValue(AstSemicolon.java:35) at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:188) at javax.el.ELProcessor.getValue(ELProcessor.java:45) at javax.el.ELProcessor.eval(ELProcessor.java:38) at org.apache.el.parser.TestAstMethodCalls.test01(TestAstMethodCalls.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Looking into this, it appears that the EL is having trouble because StringBuilder's append method is overloaded. It is instructed to call append with the character 'c', but instead is trying to coerce the character 'c' to a long and call append with the long. This chain of events seems to be kicked off in AstValue.getValue() line #157, where it's calling resolver.invoke(..). The call to resolver.invoke() is passing null as the paramTypes argument. This trickles down to BeanELResolver.invoke(), which calls Util.findMethod(). Because paramTypes is null, Util.findMethod() selects the first method it finds with the expected number of arguments. In the case above, it selects StringBuilder.append(long), which causes the problem above. 2.) Here's the second test. @Test public void test02() { ELProcessor processor = new ELProcessor(); processor.getELManager().importClass("java.util.Date"); Date result = (Date) processor.eval("Date(86400)"); Assert.assertEquals(86400, result.getTime()); } This one fails intermittently with the following stack trace. javax.el.ELException: java.lang.IllegalArgumentException at javax.el.StaticFieldELResolver.invoke(StaticFieldELResolver.java:118) at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:84) at org.apache.el.parser.AstFunction.getValue(AstFunction.java:138) at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:188) at javax.el.ELProcessor.getValue(ELProcessor.java:45) at javax.el.ELProcessor.eval(ELProcessor.java:38) at org.apache.el.parser.TestAstMethodCalls.test02(TestAstMethodCalls.java:39) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.lang.IllegalArgumentException at java.util.Date.parse(Date.java:615) at java.util.Date.<init>(Date.java:272) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:526) at javax.el.StaticFieldELResolver.invoke(StaticFieldELResolver.java:111) ... 29 more Looking into this error, it seems similar to #1. The difference is that AstFunction.getValue() line #138 is calling invoke on the resolver and passing null as the paramTypes. This trickles down to the StaticFieldELResolver.invoke() method, which calls Util.findConstructor(). Again, because paramTypes is null, Util.findConstructor() searches the available constructors for the one with the same number of arguments. The reason that this intermittently fails is because on my system, the call to Class.getConstructors() returns the list of constructs in an arbitrary order. So it fails when Date(String) is listed first, but succeeds when Date(long) is listed first.
Created attachment 30764 [details] Unit test Attaching a unit test to replicate the problem.
Thanks for the report and the unit tests. This has been fixed in trunk and will be included in 8.0.0-RC2 onwards.
*** Bug 56147 has been marked as a duplicate of this bug. ***
org.apache.el.util.ReflectionUtil#getMethod(java.lang.Object, java.lang.Object, java.lang.Class<?>[], java.lang.Object[]) // If a method is found where every parameter matches exactly, // return it if (exactMatch == paramCount) { getMethod(base.getClass(), m); } I haven't fully understand the recent patches but I think it should be return getMethod(base.getClass(), m); as the comment says.
Re-open to review comment #4.
Thanks for the report. The missing return didn't change the behaviour, it just meant that the exact match wasn't returned as quickly as it could have been.
The fix for this has broken one of our EL expressions, we have an overloaded method like so: doSomething(HttpServletRequest a, String b, String c, String d); doSomething(String a, String b, String c, String d); and we end up with an error 'Unable to find unambiguous method'. It is supposed to invoke the first method. From what I can tell it's because when it is assessing the suitability of each method, it doesn't find an exact match for either as the actual request object is a sub-class of HttpServletRequest, and can also be coerced into a String. Perhaps this can be fixed by prioritising sub-class matches over coercions?
(In reply to Christopher Ng from comment #7) > The fix for this has broken one of our EL expressions, we have an overloaded method like so: > > doSomething(HttpServletRequest a, String b, String c, String d); > doSomething(String a, String b, String c, String d); > ... This issue has already been reported and is tracked as bug 56425. (It has been fixed in 8.0.x for 8.0.6 onwards and in 7.0.x for 7.0.54 onwards.)
This changes added Tomcat 7.0 but It has no unit tests. Do Anyone have unit tests for Tomcat 7.0?
This change broke our code. I pasted our code here http://stackoverflow.com/questions/38709068/argument-type-of-parameterized-method-call-in-el We were able to call ${objectMapper.writeValueAsString(actionItems)} where actionItems is an ArrayList, while writeValueAsString takes an Object argument. After this change, method invocation in EL can only find the method with exact match of parameter types. And our method call is broken with NoSuchMethodException. It makes sense to find the exact match when there are method overloads. But if there is no method overload, it should return the only matched method thus it is compatible with the old code like ours.
(In reply to Hao from comment #10) > This change broke our code. Please open a new issue and attach a minimal test case that demonstrates the issue.
Hi Mark, I created a new issue yesterday https://bz.apache.org/bugzilla/show_bug.cgi?id=59939 I believe it is related this this issue. Can you please have a look? Thanks.