日志文章

2007年08月01日 08:02:20

EL2.1规范

ExpressionLanguage 2.1 Specification
注:此文档由mErcy翻译JSP2.1EL规范而来,转载请声明出处,不得用于商业性质。
1.1 EL表达式:
EL表达式规定为:eval-expressionliteral-expression,同时EL表达式支持Compositeexpressions,很多EL表达式(eval-expressionsliteral-expressions)被聚合在一起。
EL表达式被解析成数值表达式和方法表达式。其中,取值表达式去引用一个值,而方法表达式则是关联一个方法。一旦被解析之后,表达式能够被优化地计算一次或多次。
下面我们来分为:eval-expressionliteral-expressionCompositeexpressions来讲述
1.1.1Eval-expression
Eval-expression是以使用${expr}或者#{expr}结构的形式构成。两种方式都是相同的方式,能很好被解析和计算,尽管它们在使用时有着不同的意义从技术方面来说。
J2EE层规范协定来说,${expr}结构是直接计算而#{expr}结构则是延期计算,这种界定符号指出了在J2EE层两种表达式类型的语义上面的区别。#{expr}这种界定符号被称为延迟计算是因为直到系统需要的时候才计算。而${expr}这种界定符号则是在JSP页面编译的时候就计算,就是为什么叫做直接计算的原因。
1.1.1.1作为取值表达式的计算表达式
当解析成一个取值表达式的时候,eval-expression能被计算成左值和右值。若在EL中有等号操作符号出现,右值是类型出现在等号的右边的表达式,左值同理。
  右值比如:
     <input type="text"value="${customer.name}"/>
     <h:form>
  以下面这个例子为例:
        <h:inputText
        id="email"
        value="#{checkOutFormBean.email}"
        size="25"maxlength="125"
       validator="#{checkOutFormBean.validateEmail}"/>
     </h:form>
当表单被提交的时候,在申请计算的阶段,Faces计算EL表达式#{checkOutFormBean.validateEmail}作为一个数据接口的引用,这个数据结构的数值是被一个表单相关联的输入参数设置。因此,表达式的结果表现成一个数据结构的引用,或者为一个左值。
在翻译阶段,那个相同的表达式被计算,它产生特殊值关联右值对象,作为JSP实例。
一个左值合法语法是右值合法语法的子集。在特殊情况,一个左值只能由单个变量(比如${name})或者一个从某个对象中解析属性的组成,通过. []操作符(比如 ${employee.name}
在解析取值表达式时,一个预期的类型是被提供的。拿右值为例,预期的类型是表达式计算被强制的结果。以左值为例,预期的类型是被忽略的,并且在属性被设置之前,提供的值是被强制为一个表达式指向实际的属性类型。在后面提供了类型转换
1.1.1.2作为方法表达式的计算表达式
  在某种情况,计算表达式会描述成引用一个方法而不是模型对象。
比如,在JSF中,组建标记也提供了引用方法的属性的集合,这些方法能够执行特定为组建标签关联的函数。为了支持这些类型的表达式,EL定义了方法表达式(ELclass MethodExpresssion)
  <h:inputText
        id="email"
        value="#{checkOutFormBean.email}"
        size="25"maxlength="125"
       validator="#{checkOutFormBean.validateEmail}"/>
     </h:form>
以上面的例子,validator属性使用了关联方法表达式类型的表达式。做为一个取值表达式,表达式的计算(调用函数)被延期并且在生命周期内的合理的瞬间能够被底层的技术处理。
方法表达共享相同的左值语法,它只能由单个变量(比如${name})或者一个从某个对象中解析属性的组成,通过. []操作符(比如${employee.name})。关于预期返回值类型和参数类型的信息提供在方法被解析的时候。
方法表达式被计算在其引用的方法的调用时候或者获取引用的方法信息。计算之上,ELAPI 验证方法必须一致于预期方法的签名在解析时候。因此,没有方法表达式的强制
1.1.2字面表达式
  一个字面表达式不使用${expr}或者#{expr}结构并且简单地计算String类型文本表达式。在EL上,一个预期某个类型不止提供String。比如:
表达式:Aloha!类型:String 结果:Aloha
      true       Boolean   Boolean.True
为了生成字面值包括字符串"${"或者"#{",开发人员能够选择使用组合表达式比如下面:
     ${'${'}exprA}
     #{'#{'}exprB},这里结果是${exprA}#{exprB}
两者选一个,使用转义字符\$\#能够被用于转义,否则,会被处理为取值表达式。
     \${exprA}
     \#{exprB},这里结果是${exprA}#{exprB}
字符表达式能够用在任何取值表达式使用的地方。一个字符表达式也能使用一个必须要有返回值的方法。若他们的返回值不是String类型,他们会强制类型转换。
1.1.3.组合表达式:
在多个EL表达式被组合一起的地方,EL也支持组合表达式。取值表达式从左到右北计算,强制成String类型,并且连接任何一个插入字面表达式。
举个例子,组合表达式 "${firstName}${lastName}"是由三个EL表达式组合而成,取值表达式"${firstName}""${lastName}",表达式""
一旦EL计算,结果会按照EL类型转换规则把从预期的类型强制成String类型。
混合${}#{}的结构在组合表达式中是非法的。这种限制的导入是为了避免用户想要使${expr}还是#{expr}指令来计算表达式的含糊不清。举个例子,前面我们提到了,${}是直接计算并且#{}是延迟计算在J2EEweb层规范的协定中,这就意味这EL表达式在J2EEweb层,开发人员不能强制直接计算那些组合表达式和间接计算的其余部分。这种限定可能会在未来的版本中回取消,从而为更高级的EL应用模式得到允许。
组合表达式能够在任何EL表达式除了方法表达式之外的地方使用。仅仅单个取值表达式中能解析方法表达式。
1.1.4.语法约束
取值表达式精确地被解析和被计算,在底层的技术导入约束,在EL表达式出现时,语法在使用遵循这些约束。
比如,在JSP2.1#{}表达式都只能使标签属性接受延迟表达式才被允许,若使用#{}在其他的地发挥报错误。
1.2. 字面值
有一些字面值作为booleanintegerfloatingpoint,stringnull类型在取值表达之中。
Boolean true false
Integer - 参看integerLiteral
Floating point -参看FloayPointLiteral
String - 单引号和双引号 ' 转义成 \', " 转义成 \",\ 转义成\\。引号只是需要需要转义在string封装值在相同的引号类型。
1.3. 错误,警告、默认值
表达式语言已经被设计出来作为web表示层应用程序。在使用时,经验建议最重要的是能够提供尽可能好的表述来设计,甚至在页面中有的一点错误。为了达到这个需求,EL不提供警告,只是提供默认值和错误。默认值都是类型正确的值,这些值被子表达式赋值当有问题时候。一个错误是异常的抛出(通过EL使用的环境来处理异常)。
1.4.解析模型对象和他们的属性
一个核心的概念在EL中,就是计算模型对象名称到一个对象,并且在一个表达式中分离属性应用于对象(操作符. [])。
EL API提供一个一般化机制,解析器,通过底层技术实现并且定义了规则,它管理模型对象名称的解析和他们关联属性。
1.5. 操作符[].
EL遵照的ECMAScript来统一处理.[] 操作符
expr-a.identifier-b 等于expr-a["identifier-b"];验证器 identifier-b被用于构造一个字面的值作为一个验证器。
计算expr-a[expr-b]:
  • 计算expr-a的值放到value-a
         
  • vaule-a等于null
如果expr-a[expr-b]作为末尾的一个属性被解析:
若表达式一个值表达式并且ValueExpression.getValue(context)被调用
,作为初始化表达式计算,返回null

否则,抛出PropertyNotFoundException的异常.(尝试着去分离引用null                        作为左值)
否则,返回null
  • 计算expr-b的值放到value-b
         
  • value-b等于null;
         
    • 如果expr-a[expr-b]作为末尾的一个属性被解析:
                 
      • 若表达式是一个取值表达式并且ValueExpression.getValue                  (context)方法被调用去初始化表达式的计算,返回null
                         
      • 否则,抛出一个PropertyNotFoundException.
                         
      • 否则返回一个null
                   
           
         
  • 若表达式是一个取值表达式:
         
      • 如果expr-a[expr-b]作为末尾的一个属性被解析:
                         
        • ValueExpression.getValue(context)方法被调用去初始化表达式的计算,则调用elResolver.getValue(context.value-a,value-b)方法。
                                 
        • ValueExpression.getType(context)方法被调用,调用elResolver.getType(context,value-a,value-b)方法。
                                 
        • ValueExpression.isReadOnly(context)方法被调用,则调用elResolver.isReadOnly(context,value-a,value-b)方法。
                                 
        • ValueExpression.setValue(context,val)被调用,则调用elResolver.setValue(context,value-a,value-b,val)方法。
                           
                         
      • 否则,调用elResolver.getValue(value-a,value-b)
                   
         
  • 否则,表达式则是一个方法表达式:
         
    • expr-a[expr-b]作为末尾的一个属性被解析:
                 
      • 强制value-b转化成String
                         
      • 在解析时,寻找对象vaule-a上的value-b方法和提供预想的方法参数类型集合。如果不存在这些,或者返回的类型不能匹配预想的回返类型(即方法签名不同),则抛出一MethodNotFoundException
                         
      • MethodExpression.invoke(context,params)被调用,则通过传递过来参数来调用相应的方法。
                         
      • MethidExpression.getMethodInfo(context)被调用,构建和返回一个MethodInfo对象。
                   
                 
    • 否则,调用elResolver.getValue(value-a,value-b)
           
1.6算术操作符号:
算术操作只被在Integer(BigIntegerLong)类型和浮点(BigDecimal和双精度型)值.有五个操作符:
加法:+
减法:-
乘法:*
除法:/and div
求余:%and mod
算术操作符的计算在下面的章节中描述。AB作为计算的字表达式。
  1.6.1 二元操作符- A {+ -*} B
  • 若      A B      都是null,则返回(Long)0
         
  • 若      A B      属于BigDecimal类型,或者都是,那么:
         
    • 若操作符为+,返回a.add(b)
                 
    • 若操作符为-,返回a.subtract(b)
                 
    • 若操作符为*,返回a.multiply(b)
           
         
  • 若      A B      属于 Float, Double,或者包含      Stringe或则E
         
    • AB属于BigInteger类型,把AB强制转化成BigDecimal类型并且应用操作符
                 
    • 否则,AB强制成Double类型并且申请操作符
           
         
  • 若      A B      属于 BigInteger类型,强制他们成为BigInteger类型,然后:
         
    • 若操作符为+,返回a.add(b)
                 
    • 若操作符为-,返回a.subtract(b)
                 
    • 若操作符为*,返回a.multiply(b)
           
         
  • 否侧,把AB强制成Integer,并且应用符操作符。
         
  • 若操作符产生异常,那么报错误。
1.6.2 二元操作符- A {/div} B
  • 若      A B      都是null,则返回(Long)0
         
  • A      B 一个属于BigDecimal或      一个属于BigInteger,都强制成BigDecimal并且返回A.divde(B,BigDecimal.ROUND_HALF_UP)
         
  • 否则,AB都强制成为Double类型并且申请操作符
         
  • 若操作符产生异常,那么报错误。
  1.6.3 二元操作符- A {% mod} B
  • 若      A B      都是null,则返回(Long)0
         
  • 若      A B      属于 Float, Double,或者包含      Stringe或则E,都强制成Double并且申请操作符。
         
  • 若      A B      属于 BigInteger类型,都强制成BigInteger返回A.remainer(B)
         
  • 否则强制成Long并且申请操作符。
         
  • 若操作符产生异常,那么报错误。
  1.6.4 一元操作符 -A
  • 若      A null,则返回(Long)0      
         
  • 若      A 属于 BigDecimal类型或则      BigInteger类型,或则A.negate()
         
  • 若      A String类型:
         
    • A            含有eE,强制成Double类型并申请操作符
                 
    • 否则强制成Long类型并申请操作符
                 
    • 操作符产生异常,那么报错误。
           
         
  • 若      A属于      ByteShortIntegerLongFloatDouble
         
    • 保留原类型,并且申请操作符
                 
    • 若操作符产生异常,那么报错误。
           
         
  • 否则,报错误
1.7 关系操作符
     == eq
  != ne
     < lt
     > gt
  <= le
     <= ge
后面四种第二的版本符号提供使用是为了避免在XML语法中中使用实体引用和含有相同的行为,比如<行为 与 lt一样,以此类推。
  1.7.1 A { <, > <= , >= , lt , gt , le , ge } B
    • 若            A == B , <=            , le , >= 或者 ge            返回 true
                 
    • 若            A B            nullreturn            false
                 
    • 若            A B            属于            BigDecemial类型,他们都会强制转化成BigDecemial类型,并且使用A.compareTo(B)方法的返回值作为返回值。
                 
    • 若            A B            属于 Float 或            Double 都强制成为Double类型并且申请操作符
                 
    • 若            A B            属于            BigInteger,都强制成BigInteger类型并且使用A.compareTo(B)方法的返回值作为返回值。
                 
    • 若            A B            属于            ByteShortCharacterInteger,或者Long等类型都强制成为Long类型并且申请操作符。
                 
    • 若            A B            属于字符型强制成String类型,比较字符:
                 
    • A属于Comparable类型,那么:
                 
      • A.compareTo(B)抛出异常,错误。
                         
      • 否则利用A.compareTo(B)结果
                   
                 
    • B属于Comparable类型,那么:
                 
      • B.compareTo(A)抛出异常,错误。
                         
      • 否则利用B.compareTo(A)结果
                   
                 
    • 否则,报错误
           
     1.7.2 A { == !=, eq , ne } B      
    • 若            A == B,申请操作
                 
    • 若            A B            属于 BigDecemial类型,他们都会强制转化成BigDecemial类型,然后:
                 
      • 若操作符为                  == 或者 eq                  , 返回 A.equals(B)
                         
      • 若操作符为                  != 或者 eq                  , 返回 !A.equals(B)
                   
                 
    • 若            A B            属于 Float 或            Double 都强制成为Double类型并且申请操作符
                 
    • 若            A B            属于 BigInteger,都强制成BigInteger类型,然后:
                 
      • 若操作符为                  == 或者 eq                  , 返回 A.equals(B)
                         
      • 若操作符为                  != 或者 eq                  , 返回 !A.equals(B)
                   
                 
    • 若            A B            属于            ByteShortCharacterInteger,或者Long等类型都强制成为Long类型并且申请操作符。
                 
    • 若            A B            属于 Boolean,都强制成Boolean,并且申请符号。
                 
    • 若            A B            属于 enum,都强制成enum,并且申请符号。
                 
    • 若            A B            属于字符型强制成String类型,比较字符:
                 
      • 否则,如果当调用A.equals(B)产生错误,则报错误。
                         
      • 否则,申请符号,并且使用A.equals(B)的结果
                   
           
1.8.逻辑操作符
逻辑操作符有:
        && and
        || or
        ! not
计算逻辑操作符的说明在下面章节中:
1.8.1 二元操作符- A {&& ||andor} B
        A B强制成Boolean,申请符号
操作符停止计算,能够由表达式来决定,比如:Aand B and C and C
如果B等于false,然后只有 AB 计算。
     1.8.2 一元操作符{! ,not } A
        A强制成Boolean,申请操作符
1.9 空值操作符-empty A      
空值操作符是一种前缀操作符,他被使用决定于一个值是否空或者null
计算空值 A
  • 若      A 等于 null,返回true
         
  • 否则如果      A 是空String,返回      true
         
  • 否则如果      A 是空array,返回      true
         
  • 否则如果      A 是空Map,返回      true
         
  • 否则如果      A 是空Collection,返回      true
         
  • 否则返回      false
1.10.条件操作符A ? B: C
计算 BC,结果依赖于A的计算
强制成Boolean
A等于 true,计算结果为B
A等于 false,计算结果为C
1.11.括号操作符
括号操作符能够改变计算的优先级,比如:${a*(b+c)}(先计算b+c
1.12.操作符优先级
        [] .      
    ()
    - not ! empty (一元操作符)
        * / div % mod
        + - (二元操作符)
        < > <= >= lt gtle ge
        == != eq ne
    && and
    || or
    ? :
带有参数合理的函数拥有的优先级超过符号的优先级。因此,表达式${c?b:f()},是一个非法的,因为b:f()被解析成一个合理的函数而不是作为一个条件表达式。通常,()操作符能被用作确定优先级,比如:${c? b :(f()) }
1.13.保留字:
下列的语言保留字不能由做法标识符:
           and      eq      gt      true      instanceof
           or      ne      le      false      empty
           not      lt      ge      null      div      mod      
注:这些中的很多保留字没有用到语言中,但是他们可能会在未来中使用,所以开发人员必须避免使用这些(保留)字
1.14.函数:
EL有些限定的函数,重用XML命名空间(和属性)限定,XSL函数,和JSP自定义动作等概念。函数都映射到publicstatic 方法在Java类中。
限定n个数组函数完全语法:
           [ns:]f([a1[,a2[,...[,an]]]])
    ns是命名空间的前缀,f是函数的名字,a是函数的参数。
EL函数被映射,解析和绑定在解析的时候。它是由FunctionMapper类负责提供映射命名空间限定函数,这个函数使用有特殊的类的static方法在表达式创造。若没有FunctionMapper类被提供,函数会失效。
1.15.变量:
就像FunctionMapperEL表达式中添加函数那样提供一种灵活的机制,VariableMapper为支持EL变量的概念提供一种灵活的机制。一个EL变量不是直接引用一个模型变量而能够通过ELResolver类被解析出来之后引用,而不是EL变量引用一个EL表达式。EL表达式的计算产生关联一个EL表达式数值。
EL变量被映射,解析和绑定在解析的时候。它是由VariableMapper类负责提供EL变量映射到ValueExpressions当表达式创建时。若没有VariableMapper类被提供,函数会失效。
参看 javax.el包中的描述更多细节。
1.16.枚举:
统一EL支持JavaSE5中的枚举类型。强制规则包括处理枚举类型在下面的章节中。同时,引用在EL表达式中枚举类型实例化对象的值,通过下面的强制转化规则使用字面值字符串去强制执行。比如,我们说,我们有一个枚举类型叫做Suit,它有成员Heart,Diamond,Club,Spade。并且,我们说,我们有一个引用在EL表达式中,mySuit,就是Spade。如果你想要去测试枚举Spade相等性,你能说${mySuit== Enum.valueOf(Suit.class,'Spade')
1.17.类型转换:
每个表达式被计算在预料类型的上下文中。表达式计算结果可能不会精确地匹配预料的类型,所以应用规则描述在下面章节。
     1.17.1强制X值转化成类型Y:
  • X是原始(原生)类型,那么让X等于X的包装类型。否则,让X不变。
         
  • Y是原始(原生)类型,那么让Y等于Y的包装类型。否则,让Y不变。
         
  • 应用下面的章节中强制转化XY
         
  • Y是原始(原生)类型,那么结果被拆包强制结果找到。若强制结果是null,那么报错。
         
  • Y不是原始(原生)类型,结果就是强制结果。
比如;如果强制int类型成String类型,那么包装int类型成Integer类型并且利用这个规则强制Integer类型成String类型。或者如果强制String成一个Double,应用规则强制String类型成Double类型,确定结果Double不是null
1.7.2强制AString类型
    • 如果AString类型,则返回A
                 
    • 否则,若A等于null,则返回""
                 
    • 否则,若A是枚举类型,则返回A.name()
                 
    • 否则,若A.toString()抛出throws一个异常,错误
                 
    • 否则,返回A.toString()
           
1.7.3强制ANumber类型N
      • A等于null或                  "",返回0.
                         
      • A属于Character类型,转化Anew                  Short((short)a.charValue()),并且应用以下规则。
                         
      • A属于Boolean类型,则报错
                         
      • A属于Numner类型,则直接返回A
                         
      • A属于Numner类型,安静地强制成Number类型利用下面的算法:
                         
        • N属于BigInteger类型,
                                 
          • A是一个BigDecimal,则返回A.toBigInteger()
                                         
          • 否则,返回BigInteger.valueOf(A.longValue())
                                   
                                 
        • N属于BigDecimal类型,
                                 
          • A属于BigDecimal类型,返回new                              BigDecimal (A)
                                         
          • 否则,返回new                              BigDecimal(A.doubleValue())
                                   
                           
                         
      • N属于Byte类型,返回new                  Byte(A.byteValue())
                         
      • N属于Short类型,返回new                  Short(A.shortValue())
                         
      • N属于Integer类型,返回new                  Integer(A.intValue())
                         
      • N属于Long类型,返回new                  Long(A.longValue())
                         
      • N属于Float类型,返回new                  Float(A.floatValue())
                         
      • N属于Double类型,返回new                  Double(A.doubleValue())
                         
      • 否则,错误。
                         
      • A属于String类型,那么:
                         
        • 如果N属于BigDecimal,那么:
                                 
            •                                    如果new                                    BigDecimal(A)抛出一个异常,则报错误。
                                                 
            •                                    否则,返回new                                    BigDecimal(A)
                                           
                           
                         
      • N属于BigInteger,那么:
                         
        • 如果new                        BigInteger(A)抛出一个异常,则报错误。
                                 
        • 否则,返回new                        BigInteger(A)
                                 
        • N.valueOf(A)抛出一个异常,则报错误。
                                 
        • 否则,返回N.valueOf(A)
                           
                         
      • 否则,报错误。
                   
1.7.4强制ACharacter
    • A等于null            或则 "",返回(char)0
                 
    • A属于Character,返回A
                 
    • A属于Boolean类型,则报错
                 
    • A属书Number类型,安静地强制转化成Short,然后返回一个Character,它的数值等于对应的Short
                 
    • A是字符型,返回A.charAt(0)
                 
    • 否则,报错误
           
1.7.5强制成Boolean
  • A等于null      "",返回      false
         
  • 否则,若A属于Boolean,返回A
         
  • 否则,若A是一个String类型,并且Boolean.valueOf(A)不抛出异常,并且返回它。
         
  • 否则,报错误。
1.7.6强制A成一个枚举型T
    • A等于null,返回null
                 
    • A被分配成T,则安静地强制转化
                 
    • A等于"",返回null
                 
    • A是一个字符串调用Enum.valueOf(T.getClass(),A)方法,并且返回这个结果
           
1.7.7强制成任何其他类型T
    • A等于null,则返回null
                 
    • A分配成T,则安静地强制转化。
                 
    • A为一个字符串,并且T没有含有PropertyEditor
                 
      • A等于"",返回null
                         
      • 否则,报错误。
                   
                 
    • A为一个字符串并且TPropertyEditor抛出一个异常:
                 
        • A等于"",返回null
                                 
        • 否则报错
                           
                 
    • 否则,应用TPropertyEditor
                 
    • 否则,错误。
           





Tags: EL21   EL   EL规范   SUN EL   JSP2  

类别: J2EE开发经验 |  评论(0) |  浏览(3126) |  收藏
发表评论