uel
  1. uel
  2. UEL-12

Coercion of null Boolean to false is unexpected

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: current
    • Fix Version/s: milestone 1
    • Component/s: www
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: Sun

    • Issuezilla Id:
      12

      Description

      Sent to jsr-314-open (JSF EG list)

      >>>>> On Tue, 13 Oct 2009 23:03:35 +0200, Martin Marinschek

      MM> Hi all,
      MM> I don't know if we discussed this already, but today the coercion
      MM> issue in the EL made me loose a few hours again. I've had this before,
      MM> but seemingly forgot about it - time to follow up on this.

      MM> The issue in short: collapsed="#

      {bb.collapsed}

      "

      MM> Boolean getCollapsed()

      { MM> return null; MM> }

      MM> will lead to a value of "false" for the collapsed attribute if
      MM> java.lang.Boolean is set as the expected type of the corresponding
      MM> value-expression, according to the EL spec. Hrmmpf.

      MM> You can read more in this blog-entry:
      MM> http://www.irian.at/blog/blogid/unifiedElCoercion/#unifiedElCoercion

      MM> Coerce A to Boolean

      MM> * If A is null or "", return false
      MM> * Otherwise, if A is a Boolean, return A
      MM> * Otherwise, if A is a String, and Boolean.valueOf(A) does not
      MM> throw an exception, return it

      MM> so it DOES touch the nulls. I don't know either who came up with this.

      DA> Right, I agree with you. I'm saying that this is silly behavior. Either it
      DA> should leave null alone or choose to convert it only if the expected-type
      DA> is a primitive (in this case a primitive boolean).

      MM> Yes, I agree, this is the way it should be - the way it currently
      MM> works is really causing pain for users.

        Activity

        Hide
        mojavelinux added a comment -

        The coercion occurs when the ValueExpression#getValue(ELContext) is invoked on a
        ValueExpression object whose ValueExpression#getExpectedType() is not null.

        The implementation of the offending assumption can be found in the following
        method, and delegates:

        com.sun.el.lang.ELSupport#coerceToType(Object, Class)

        With regard to the example in this bug report, here is the logic for coercing a
        boolean value:

        if (obj == null || "".equals(obj))

        { return Boolean.FALSE; }

        if (obj instanceof Boolean)

        { return (Boolean) obj; }


        if (obj instanceof String)

        { return Boolean.valueOf((String) obj); }
        Show
        mojavelinux added a comment - The coercion occurs when the ValueExpression#getValue(ELContext) is invoked on a ValueExpression object whose ValueExpression#getExpectedType() is not null. The implementation of the offending assumption can be found in the following method, and delegates: com.sun.el.lang.ELSupport#coerceToType(Object, Class) With regard to the example in this bug report, here is the logic for coercing a boolean value: if (obj == null || "".equals(obj)) { return Boolean.FALSE; } if (obj instanceof Boolean) { return (Boolean) obj; } if (obj instanceof String) { return Boolean.valueOf((String) obj); }
        Hide
        mojavelinux added a comment -

        An easier way to duplicate the problem is to create a select menu for a boolean
        property.

        Create a setter for the boolean property:

        public void setOptionValue(Boolean optionValue)

        { System.out.println("Option value is " + optionValue); }

        <h:selectOneMenu value="#

        {bb.optionValue}

        ">
        <f:selectItem itemValue="#

        {null}

        " itemLabel="[NULL]"/>
        <f:selectItem itemValue="#

        {true}

        " itemLabel="TRUE"/>
        <f:selectItem itemValue="#

        {false}

        " itemLabel="FALSE"/>
        </h:selectOneMenu>

        Select the [NULL] value and submit the form. You'll see the following output in
        the log:

        Option value is false

        Truthfully, the option value should be null. There is no way for you to know
        that the user selected the null value and not the false value because of
        coercion.

        We introduced a workaround for this exact problem in JSF 2.0 with the context
        param javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL. But really I
        think that is just a stopgap solution to getting EL to respect null values.

        Show
        mojavelinux added a comment - An easier way to duplicate the problem is to create a select menu for a boolean property. Create a setter for the boolean property: public void setOptionValue(Boolean optionValue) { System.out.println("Option value is " + optionValue); } <h:selectOneMenu value="# {bb.optionValue} "> <f:selectItem itemValue="# {null} " itemLabel=" [NULL] "/> <f:selectItem itemValue="# {true} " itemLabel="TRUE"/> <f:selectItem itemValue="# {false} " itemLabel="FALSE"/> </h:selectOneMenu> Select the [NULL] value and submit the form. You'll see the following output in the log: Option value is false Truthfully, the option value should be null. There is no way for you to know that the user selected the null value and not the false value because of coercion. We introduced a workaround for this exact problem in JSF 2.0 with the context param javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL. But really I think that is just a stopgap solution to getting EL to respect null values.
        Hide
        kchung added a comment -

        This is fixed in EL 3.0: coercing a null to Boolean is null instead of false.

        Show
        kchung added a comment - This is fixed in EL 3.0: coercing a null to Boolean is null instead of false.

          People

          • Assignee:
            Unassigned
            Reporter:
            Ed Burns
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: