Bug 43285 - Missing EL Coercion causes argument type mismatch
Summary: Missing EL Coercion causes argument type mismatch
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 6
Classification: Unclassified
Component: Servlet & JSP API (show other bugs)
Version: 6.0.14
Hardware: Other Windows XP
: P2 enhancement (vote)
Target Milestone: default
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
: 45040 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-09-02 13:14 UTC by Bernhard Huemer
Modified: 2014-02-17 13:53 UTC (History)
4 users (show)



Attachments
Sample web application reproducing the error (3.94 KB, application/x-zip-compressed)
2007-09-02 13:19 UTC, Bernhard Huemer
Details
Proposed patch (1.10 KB, patch)
2007-09-02 13:20 UTC, Bernhard Huemer
Details | Diff
Proposed patch taking care of primitive types (1.07 KB, patch)
2008-05-14 14:07 UTC, Nils Eckert
Details | Diff
Proposed patch taking care of primitive types (configurable) (1.80 KB, patch)
2008-05-19 04:11 UTC, Nils Eckert
Details | Diff
Proposed patch taking care of primitive types (configurable) (1.79 KB, patch)
2008-05-19 04:23 UTC, Nils Eckert
Details | Diff
Proposed patch taking care of primitive types (configurable) (1.86 KB, patch)
2008-05-29 02:28 UTC, Nils Eckert
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Bernhard Huemer 2007-09-02 13:14:26 UTC
I'll attach a sample web application reproducing the error. Note that this error
only occurs when using Tomcat 6.0.x (i.e. it works with Jetty as it uses Sun's
EL RI). Moreover it doesn't matter which JSF implementation you're using to
reproduce the error (I just wanted to mention that as it's definitely no bug in
MyFaces even though the following stack trace shows a FacesException).

The exception stack trace:
javax.faces.FacesException: Exception while calling broadcast on component :
{Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /home.jsp][
Class: javax.faces.component.html.HtmlForm,Id: j_id_jsp_923754602_1][Class:
javax.faces.component.html.HtmlCommandButton,Id: j_id_jsp_923754602_3]}
        at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:494)
        at javax.faces.component.UICommand.broadcast(UICommand.java:105)
        at javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:292)
        at javax.faces.component.UIViewRoot.process(UIViewRoot.java:209)
        at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:117)
        at
org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:32)
        at
org.apache.myfaces.lifecycle.LifecycleImpl.executePhase(LifecycleImpl.java:95)
        at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:70)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:144)
        at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
        at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
        at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
        at
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
        at
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
        at java.lang.Thread.run(Thread.java:619)
Caused by: org.apache.jasper.el.JspELException: /home.jsp(12,3)
'#{numberBean.number}' java.lang.IllegalArgumentException: argument type mismatch
        at
org.apache.jasper.el.JspValueExpression.setValue(JspValueExpression.java:94)
        at
org.apache.myfaces.event.SetPropertyActionListener.processAction(SetPropertyActionListener.java:72)
        at javax.faces.event.ActionEvent.processListener(ActionEvent.java:48)
        at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:489)
        ... 20 more
Caused by: java.lang.IllegalArgumentException: argument type mismatch
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at javax.el.BeanELResolver.setValue(BeanELResolver.java:108)
        at javax.el.CompositeELResolver.setValue(CompositeELResolver.java:68)
        at
org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.access$501(FacesCompositeELResolver.java:46)
        at
org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver$6.invoke(FacesCompositeELResolver.java:132)
        at
org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.invoke(FacesCompositeELResolver.java:148)
        at
org.apache.myfaces.el.unified.resolver.FacesCompositeELResolver.setValue(FacesCompositeELResolver.java:128)
        at org.apache.el.parser.AstValue.setValue(AstValue.java:114)
        at org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:249)
        at
org.apache.jasper.el.JspValueExpression.setValue(JspValueExpression.java:85)
        ... 23 more
Comment 1 Bernhard Huemer 2007-09-02 13:19:01 UTC
Created attachment 20757 [details]
Sample web application reproducing the error
Comment 2 Bernhard Huemer 2007-09-02 13:20:34 UTC
Created attachment 20759 [details]
Proposed patch
Comment 3 Tim Funk 2007-12-26 18:13:36 UTC
patch applied to trunk
vote in place on 6.0.x HEAD
Comment 4 Mark Thomas 2007-12-30 14:11:41 UTC
This has been committed to 6.0.x and will be included in 6.0.16 onwards.

Thanks for the patch.
Comment 5 Subba Ayyagari 2008-02-19 15:38:24 UTC
This introduced a new bug now. In 6.0.14, when you have a selecItem whose empty
value is selected (value=""), and the binding datatype was Long, EL evaluation
would set it to NULL. Now, its setting it to 0. 
Comment 6 Subba Ayyagari 2008-02-19 15:48:56 UTC
To add to my comment above: 

Here is my bean:
MyBean { 
   private Long number; 
   ...//getter 
   .. //setter 
   .. // other methods
}

Here is my JSP (JSF Page rather):
<h:selectOneMenu
    value="#{myBean.number}"
    required="false"
    converterMessage="Number value is invalid">
    <f:selectItems value="#{myBean.allNumbers}"/>
</h:selectOneMenu>

myBean.allNumbers is implemented as follows:

public List<SelectItem> getAllNumbers() {
   List<SelectItem> list = new ArrayList<SelectItem>(0);
   list.add(new SelectItem("", "--SELECT--"));   // NOTE: this causes the issue
   list.add(new SelectItem("1", "ONE"));
   list.add(new SelectItem("2", "TWO"));
   list.add(new SelectItem("1", "THREE"));
   return list;
}

Now, when i don't select a value (ie., leave the drop down on --SELECT--) for
the Number and submit the form, Tomcat 6.0.16 would set the myBean.number to 0.
Until Tomcat 6.0.14, the value is NULL.

Why is this important? It ends up putting 0's in the database instead of NULL's.

Thanks
Comment 7 Bernhard Huemer 2008-03-23 13:05:39 UTC
Note that the Expression Language specification requires this behaviour, see "1.2.1.1 Eval-expressions as value expressions": "In the case of lvalues [...] the provided value is coerced to the actual type of the property the expression points to, before that property is set." Furthermore, according to the coercion rules defined in the section "1.18.3 Coerce A to Number type N" the Expression Language implementation has to coerce both null and "" to 0. 
As you can see, this behaviour is not only what one would expect but also what the specification requires.
Comment 8 Mark Thomas 2008-04-09 15:37:17 UTC
Changing back to fixed based on previous comment.
Comment 9 Nils Eckert 2008-05-14 14:03:33 UTC
As far as this fix changes the behavior in a significant way it is a major change that will cause a lot of trouble.

With this fix it is not possible to deal with 'optional' number fields. We don't no whether the user entered the value 0L or 'nothing'. All of our SearchForms where we add restrictions for not-null fields are not working any more. To use bindings for such a simple thing is as nonpractical as using String for number fields. 

You are right that your fix follows the JSP 2.1 specification. But even Sun's reference implementation allows null-values.

To enable Tomcat < 6.0.15 and JSF 1.2 Users to update to Tomcat > 6.0.16 I would recommend to make this behavoir configurable (e.g. with an context-param) or follow the RI and allow null-values.

I will provided an other patch that solves Bernhards problem but is aware of null values. It assigns the value without coercion if it is assignable and uses coerceToType instead.
Comment 10 Nils Eckert 2008-05-14 14:07:42 UTC
Created attachment 21962 [details]
Proposed patch taking care of primitive types

This patch extends the original AstValue.java with care about primitive types and not assignable values. It does not take care about the JSP 2.1 specification as far as it makes Objects nullable. It follows Suns RI EL-Implementation.
Comment 11 Mark Thomas 2008-05-17 10:48:44 UTC
That the RI has a bug and is not spec compliant is not a justification for deliberately inserting the same bug in Tomcat. That said, I am not against an enhancement that makes this configurable.

Jasper can't get at the Tomcat context configuration without making Jasper dependant on Tomcat internals, something we try not do to. To be consistent with similar configuration options it could be done with a system property (see http://svn.apache.org/repos/asf/tomcat/trunk/webapps/docs/config/systemprops.xml for examples). The code would need to ensure that setting org.apache.catalina.STRICT_SERVLET_COMPLIANCE overrides the new setting that allows nulls.
Comment 12 Nils Eckert 2008-05-19 04:11:14 UTC
Created attachment 21981 [details]
Proposed patch taking care of primitive types (configurable)

Configurable with VM-parameter "org.apache.catalina.STRICT_JSP_COMPLIANCE"
Comment 13 Nils Eckert 2008-05-19 04:23:09 UTC
Created attachment 21982 [details]
Proposed patch taking care of primitive types (configurable)

I renamed the parameter to "org.apache.catalina.STRICT_JSP_COMPLIANCE" and had forgotten to refactor the corresponding  field-name. Please feel free to rename this field / parameter if needed.
Comment 14 Mark Thomas 2008-05-19 11:49:04 UTC
*** Bug 45040 has been marked as a duplicate of this bug. ***
Comment 15 Nils Eckert 2008-05-29 02:28:09 UTC
Created attachment 22028 [details]
Proposed patch taking care of primitive types (configurable)

Fixing NullpointerException in isAssignable when assigning values to a Map (targetClass is null then).
Comment 16 Mark Thomas 2008-06-09 09:45:39 UTC
I have applied your patch to make this optional to trunk and proposed it for 6.0.x
Comment 17 Konstantin Kolinko 2009-05-04 03:42:42 UTC
The patch is applied to 6.0 in r671358 (2008-06-24) and is in 6.0.17 onwards.

The system property that controls this feature is
org.apache.el.parser.COERCE_TO_ZERO

http://svn.apache.org/viewvc?rev=671358&view=rev
http://tomcat.apache.org/tomcat-6.0-doc/config/systemprops.html
Comment 18 Richard Kennard 2009-06-16 19:39:30 UTC
Please note this feature/bug is being tracked (and hopefully fixed!) at:

https://jsp-spec-public.dev.java.net/issues/show_bug.cgi?id=183