Tomcat 8 (and 9) coerce behaviour, null strings are incorrectly set as empty strings
Asked Answered
A

1

7

I have just migrated to Tomcat 8. I used to work with system property org.apache.el.parser.COERCE_TO_ZERO=false so empty strings, numbers, booleans etc. are treated as null.

In Tomcat 8, EL 3.0, it is supposed to be the default but it is in fact converting null string to empty string "" on JSF side.

It is supposed to be a bug and it is supposed to be corrected but I'm not able to get it working in TomEE snapshot (Tomcat 8.0.27.0, MyFaces 2.2.8).

Angilaangina answered 25/10, 2015 at 19:37 Comment(2)
Related? stackoverflow.com/a/31020728Tasker
Yes, indeed, thank you!Angilaangina
T
11

This is a bug in the EL 3.0 specification. Since EL 3.0, as consequence of overzealous fix of JSP spec issue 184, null will be coerced back to empty string before the model value setter is invoked. Basically, the javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL doesn't have any affect anymore. See also JSF issue 3071 and EL spec issue 18.

Basically, to solve this problem you need to provide either a custom EL resolver, or to replace/upgrade the EL implementation (or simply the whole server as it's the one actually providing EL out the box) to a version with the bugfix. The Tomcat issue 57309 which you linked is not related to this particular EL 3.0 issue of unnecessary coercion from null to empty string, it's only related to Tomcat's ignorance of the custom EL resolver.

You can solve this problem in two ways:

  1. Provide a custom EL resolver like below. Make sure that you use Tomcat 8.0.16 or newer, as specified in the Tomcat issue report you found.

     public class EmptyToNullStringELResolver extends ELResolver {
    
         @Override
         public Class<?> getCommonPropertyType(ELContext context, Object base) {
             return String.class;
         }
    
         @Override
         public Object convertToType(ELContext context, Object value, Class<?> targetType) {
             if (value == null && targetType == String.class) {
                 context.setPropertyResolved(true);
             }
    
             return value;
         }
    
         @Override
         public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
             return null;
         }
    
         @Override
         public Class<?> getType(ELContext context, Object base, Object property) {
             return null;
         }
    
         @Override
         public Object getValue(ELContext context, Object base, Object property) {
             return null;
         }
    
         @Override
         public boolean isReadOnly(ELContext context, Object base, Object property) {
             return true;
         }
    
         @Override
         public void setValue(ELContext context, Object base, Object property, Object value) {
             // NOOP.
         }
    
     }
    

    In order to get it to run, register as below in faces-config.xml:

     <application>
         <el-resolver>com.example.EmptyToNullStringELResolver</el-resolver>
     </application>
    

  2. Or, switch to Oracle EL. They already fixed it in version 3.0.1 b05 which has been available since 7 July 2014 (just pick the newest one which is 3.0.1-b10 as of today).

    Just drop javax.el.jar file in /WEB-INF/lib and add the below context param to web.xml in order to instruct MyFaces to use the Oracle EL implementation instead:

     <context-param>     
         <param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name>
         <param-value>com.sun.el.ExpressionFactoryImpl</param-value>   
     </context-param>
    

    In case you're using Mojarra, use param name com.sun.faces.expressionFactory.

As I got momentarily confused myself too, I blogged to get it all right: The empty String madness.

###See also:

Tasker answered 29/10, 2015 at 17:34 Comment(4)
Only the first solution works for me. I'm using joinfaces: github.com/joinfaces/joinfacesFrigidaire
I recently tried to upgrade from EE7 to EE8 by moving fra Tomcat 8.5 to 9.0.7 (Weld 3, Mojarra 2.3 and Jersey 2.26). Suddenly, this null/empty string started playing mayhem with my view parameters. I tried to make sense of the recommendations in this post but failed. I'm hoping BalusC will shed light on what I may be experiencing siden I was expecting all this to have blown over by now.Edithe
Upgrading from Tomcat 8.5 to 9.0.12, solution #2 above using the sun jar no longer works for me. However, returning to stackoverflow.com/users/157882/balusc EmptyToNullStringConverter published here balusc.omnifaces.org/2015/10/the-empty-string-madness.html results in empty strings being set as null on form submit.Evanesce
I'm unable to simply add the custom EL resolver due to my dependence on PrimeFaces: org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolverEdithe

© 2022 - 2024 — McMap. All rights reserved.