jsr341-experts@el-spec.java.net

[jsr341-experts] More clarifications to variable assignments

From: Kin-man Chung <kinman.chung_at_oracle.com>
Date: Thu, 15 Sep 2011 12:50:32 -0700

Assignment to EL variables turns out to be more complicated because an
EL variable

    1. Takes a ValueExpression, and not a Object instance, and
    2. Is "mapped, resolved, and bound" at parse time (EL 1.16)

I finally got it working I way I want it to. I have also updated the
wiki page, reproduced here.

================


    Assignment


      Syntax

expr-a = expr-b

    * If expr-a is an identifier (with value name-a) and name-a is an EL
      variable (i.e. it is defined in the VariableMapper), or name-a is
      not resolved by the ELResolver
          o Set name-a in the VariableMapper with the ValueExpression
            for expr-b, without evaluation.
          o Evaluate expr-b to value-b.
    * Else
          o Evaluate expr-b to value-b.
          o Evaluate expr-a, up to (but not including) the last property
            resolution.
          o If expr-a is a . or [] operator, evaluate the base to
            base-a, and the property to prop-a.
                + If base-a is null, throw a BeanNotFoundException.
                + If prop-a is null, throw a PropertyNotFoundException.
          o Invoke ValueExpression.setValue for expr-a:
            expr-a.setValue(context, value-b);
    * If ValueEpxression.getValue was called to initiate this expression
      evaluation, return value-b.
    * If ValueExpression.setValue was called to initiate this expression
      evaluation, throw a PropertyNotWritableException.

The last two bullet items ensure that the assignment operator returns
the correct value, and that it is not writable.

Note that EL variables are bound at parse time, so their assignment in
an expression only takes effect after the expression is evaluated. This
can lead to some unexpected behaviors. For example, consider the following.

   elp = new ELProcessor();
   elp.setVariable("x", "10");
   int n = elp.getValue("(x = 20) + x}";

The value of n is 30 instead of 40, because the value of x is 10 when
the expression is parsed.


      Operator Precedence

It has the lowest precedence, lower than the ?: operator.


      Example

  "x = a.b"
   If x does not exist then same as calling defineVariable("x", "#{a.b});

   "x.y = a.b"
   Set x.y = a.b. Error if x does not exist.

==============

The inclusion of variables in assignment complicates things a bit, but
is well worth it, I think. :-)

I had a little trouble getting this to work, because the current
implementation takes a copy of the VariableMapper at parse time, without
the ability to set new values to variables at evaluation time. I am
sure Mark would run into the same issue when he implements this, since
we have basically the same code base. :-)

Kin-man