Bug 56425

Summary: Unable to find unambiguous method in class String
Product: Tomcat 7 Reporter: Sebastian <sebastian.ricaldoni>
Component: JasperAssignee: Tomcat Developers Mailing List <dev>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P2    
Version: 7.0.55   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Attachments: Test
Test

Description Sebastian 2014-04-17 19:12:41 UTC
I am experiencing an issue with my code running in tomcat 7.0.53 which is returning a JasperException Caused by: javax.el.MethodNotFoundException: Unable to find unambiguous method: class java.lang.String.replace(java.lang.String, java.lang.String)

Below is the JSP code causing the problem. This does not happen in previous versions of Tomcat including 7.0.50 and 7.0.52.


<div class="slyout-container ${object.replace('.', '_')}" data-searchbox-target="${target }">

object is of type String with values such as "module.submodule" and I want to make it "module_submodule"


Below is the stack trace. 

Caused by: org.apache.jasper.JasperException: javax.el.MethodNotFoundException: Unable to find unambiguous method: class java.lang.String.replace(java.lang.String, java.lang.String)
at org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:549)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:470)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:604)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:543)
at org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:954)
at org.apache.jsp.layouts.window_jsp._jspService(window_jsp.java:92)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:486)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338)
at org.apache.tiles.servlet.context.ServletTilesRequestContext.forward(ServletTilesRequestContext.java:241)
... 51 more
Caused by: javax.el.MethodNotFoundException: Unable to find unambiguous method: class java.lang.String.replace(java.lang.String, java.lang.String)
at javax.el.Util.findWrapper(Util.java:333)
at javax.el.Util.findMethod(Util.java:214)
at javax.el.BeanELResolver.invoke(BeanELResolver.java:174)
at org.apache.jasper.el.JasperELResolver.invoke(JasperELResolver.java:139)
at org.apache.el.parser.AstValue.getValue(AstValue.java:173)
at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:184)
at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:967)
at org.apache.jsp.WEB_002dINF.views.core.search.searchForm_jsp._jspService(searchForm_jsp.java:171)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
... 77 more


Thanks,
Sebastian
Comment 1 Konstantin Kolinko 2014-04-18 12:53:06 UTC
In the String class there is no such method as "replace(String, String)"

The methods are
replace(CharSequence, CharSequence)
replace(char, char)

Method matching was changed in 7.0.53 (implementing fix for bug 55483).

Apparently when searching for a method in Util.findWrapper() there is no distinction between "isAssignableFrom" and "isCoercibleFrom" parameters when weighting potential matches.

I do not see any place in EL specification that clarifies how method matching is performed.


By the way, for your use case I can suggest to use fn:replace() function from JSTL tag library,
http://tomcat.apache.org/taglibs/standard/
Comment 2 Mark Thomas 2014-04-25 19:55:11 UTC
Thanks for the report. This has been fixed in 8.0.x for 8.0.6 onwards and in 7.0.x for 7.0.54 onwards.
Comment 3 lafleche 2014-10-15 00:45:25 UTC
Can I see the commit where this bug was fixed?

I ran into this bug when upgrading from 7.0.50 to 7.0.55.

I was looking at the latest code for BeanELResolver.java and Util.java.

At a glance, it looks like:

getWrapper() does a bunch of fancy things including type coercion
getMethod() only looks for a perfect match.

I don't see BeanELResolver calling getWrapper() anywhere, only getMethod().

This matches the behaviour I'm seeing, where I get MethodNotFoundExceptions forr mappings like:

doFoo(Integer bar) -> doFoo(int bar)
Comment 4 Violeta Georgieva 2014-10-15 06:26:26 UTC
Hi,

This is the revision r1590121. Can you provide a test where you see the issue?

Regards,
Violeta
Comment 5 Violeta Georgieva 2014-10-22 13:48:06 UTC
Created attachment 32137 [details]
Test

The following test reproduces the issue.
Comment 6 Violeta Georgieva 2014-10-23 08:44:59 UTC
Created attachment 32140 [details]
Test

The first problem in the attached test - testBug56425a is:


java.lang.ClassCastException: java.lang.Long cannot be cast to [Ljava.lang.Object;
	at org.apache.el.lang.ELSupport.coerceToArray(ELSupport.java:497)
	at org.apache.el.lang.ELSupport.coerceToType(ELSupport.java:484)
	at org.apache.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:47)
	at javax.el.Util.isCoercibleFrom(Util.java:493)
	at javax.el.Util.findWrapper(Util.java:293)
	at javax.el.Util.findMethod(Util.java:213)
	at javax.el.BeanELResolver.invoke(BeanELResolver.java:157)
	at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:84)
	at org.apache.el.parser.AstValue.getValue(AstValue.java:157)
	at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:187)
	at javax.el.ELProcessor.getValue(ELProcessor.java:61)
	at javax.el.ELProcessor.eval(ELProcessor.java:54)
	at javax.el.TestUtil.testBug56425a(TestUtil.java:48)



I'm attaching possible fix for this ClassCastException.

The second problem in the test - testBug56425b still failes with:

javax.el.MethodNotFoundException: Unable to find unambiguous method: class javax.el.TesterBean.setValueInt(java.lang.Long)
	at javax.el.Util.findWrapper(Util.java:343)
	at javax.el.Util.findMethod(Util.java:213)
	at javax.el.BeanELResolver.invoke(BeanELResolver.java:157)
	at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:84)
	at org.apache.el.parser.AstValue.getValue(AstValue.java:157)
	at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:187)
	at javax.el.ELProcessor.getValue(ELProcessor.java:61)
	at javax.el.ELProcessor.eval(ELProcessor.java:54)
	at javax.el.TestUtil.testBug56425b(TestUtil.java:55)
Comment 7 Mark Thomas 2014-10-23 13:01:38 UTC
The array handling fix looks lood to me. I'm looking into the second issue now.
Comment 8 Mark Thomas 2014-10-23 13:18:06 UTC
The second test case is not valid. Numeric literals are treated as instances of Long (as per the EL spec). There are two matching methods. One with a paremeter of int and one with a parameter of Integer. There is no way for EL to differentiate bewtween them. The match is ambiguous (both matches would require co-ercion). Therefore Tomcat's behaviour here is correct.

I'll get the fix for the first issue committed shortly.
Comment 9 Mark Thomas 2014-10-23 13:28:28 UTC
The additional array issue has been fixed in Tomcat 8.0.x in 8.0.15 onwards. It does not occur in earlier versions.