jsp EL式でうっとうしいint/float/char

7977 ワード

詳細
EL式の計算の過程で、多くの奇妙な問題に遭遇する友人がいて、いつもとても憂鬱で、ここで私はこれらをまとめて、検索しやすいです:
1、すべての整数数字の字面量はLongタイプである.
2、すべての小さな数字の面量はDoubleタイプです.
3、「」または「宣言された文字列、すなわち「も文字列であり、charではない.
4、比較時はequals比較です.
 
次に、問題が発生する可能性のあるいくつかの例を見てみましょう.
1、
${1+2147483647}の結果はいくらですか?
Javaプログラムで実行すると-2114748648が得られ、jsp elでは2147483648が得られます.
 
2、
    Map map = new HashMap();
    map.put(new Long(1), 123);
    request.setAttribute("map", map);
    request.setAttribute("a", new Long(1));
%>
${map[1]}が正しい
${map[a]}が正しい
 
3、
    Map map = new HashMap();
    map.put(new Integer(1), 123);
    request.setAttribute("map", map);
    request.setAttribute("a", new Long(1));
    request.setAttribute("b", new Integer(1));
%>
${map[1]}エラー
${map[a]}エラー
${map[b]}が正しい
 
4、
    Map map = new HashMap();
    map.put(1.1, 123);//map.put(1.1d, 123);
    request.setAttribute("map", map);
    request.setAttribute("a", new Double(1.1));
%>
map.a=${map[1.1]}が正しい
map.a=${map[a]}が正しい
 
5、
    Map map = new HashMap();
    map.put(1.1f, 123);//map.put(new Float(1.1), 123);
    request.setAttribute("map", map);
    request.setAttribute("a", new Double(1.1));
    request.setAttribute("b", new Float(1.1));
%>
map.a=${map[1.1]}エラー
map.a=${map[a]}エラー
map.a=${map[b]}が正しい
 
6、
struts 2を組み合わせたognl式
----->mapを定義し、値スタックのコンテキスト領域に挿入します.
-------------->charをサポートしているため、正しい
${map['a']}--------->エラーです.'a'はjsp el式で文字列であり、=charではありません.
 
----->このときkeyは文字列
${map['a']}
 
ここではognlに注意してください.×××' 長さが1の場合はCharacterでなければString参照
http://jinnianshilongnian.iteye.com/blog/1870662
 
補足:
EL式仕様2.2では、以下のように定義されている.
と書く
■ The value of an IntegerLiteral ranges from Long.MIN_VALUE to
Long.MAX_VALUE
■ The value of a FloatingPointLiteral ranges from Double.MIN_VALUE to
Double.MAX_VALUE
tomcat 7.0.6実装中jasper.JAr(EL 2.2仕様を実現):
AstFloatingPointは小数を表し、AstIntegerは整数を表し、その定義は以下の通りである.
public final class AstInteger extends SimpleNode
{
  private volatile Number number;

  public AstInteger(int id)
  {
    super(id);
  }

  protected Number getInteger()
  {
    if (this.number == null) {
      try {
        this.number = new Long(this.image);
      } catch (ArithmeticException e1) {
        this.number = new BigInteger(this.image);
      }
    }
    return this.number;
  }

  public Class> getType(EvaluationContext ctx)
    throws ELException
  {
    return getInteger().getClass();
  }

  public Object getValue(EvaluationContext ctx)
    throws ELException
  {
    return getInteger();
  }
}

 
public final class AstFloatingPoint extends SimpleNode
{
  private volatile Number number;

  public AstFloatingPoint(int id)
  {
    super(id);
  }

  public Number getFloatingPoint()
  {
    if (this.number == null) {
      try {
        this.number = new Double(this.image);
      } catch (ArithmeticException e0) {
        this.number = new BigDecimal(this.image);
      }
    }
    return this.number;
  }

  public Object getValue(EvaluationContext ctx)
    throws ELException
  {
    return getFloatingPoint();
  }

  public Class> getType(EvaluationContext ctx)
    throws ELException
  {
    return getFloatingPoint().getClass();
  }
}

 
+-*/実装、ここでは+のみ:
package org.apache.el.parser;

import javax.el.ELException;
import org.apache.el.lang.ELArithmetic;
import org.apache.el.lang.EvaluationContext;

public final class AstPlus extends ArithmeticNode
{
  public AstPlus(int id)
  {
    super(id);
  }

  public Object getValue(EvaluationContext ctx)
    throws ELException
  {
    Object obj0 = this.children[0].getValue(ctx);
    Object obj1 = this.children[1].getValue(ctx);
    return ELArithmetic.add(obj0, obj1);
  }
}

ELArithmeticに依頼する.add:
 public static final DoubleDelegate DOUBLE = new DoubleDelegate();

  public static final LongDelegate LONG = new LongDelegate();

  private static final Long ZERO = Long.valueOf(0L);

  public static final Number add(Object obj0, Object obj1) {
    if ((obj0 == null) && (obj1 == null))
      return Long.valueOf(0L);
    ELArithmetic delegate;
    if (BIGDECIMAL.matches(obj0, obj1))
      delegate = BIGDECIMAL;
    else if (DOUBLE.matches(obj0, obj1))
      if (BIGINTEGER.matches(obj0, obj1))
        delegate = BIGDECIMAL;
      else
        delegate = DOUBLE;
    else if (BIGINTEGER.matches(obj0, obj1))
      delegate = BIGINTEGER;
    else {
      delegate = LONG;
    }
    Number num0 = delegate.coerce(obj0);
    Number num1 = delegate.coerce(obj1);

    return delegate.add(num0, num1);
  }

ここでは、様々なdelegate計算、その+の実装を依頼します.
public static final class LongDelegate extends ELArithmetic
  {
    protected Number add(Number num0, Number num1)
    {
      return Long.valueOf(num0.longValue() + num1.longValue());
    }

ここから私たちはその実現を見ることができる.
 
また、その規範には具体的な字面量が規定されています.
と書く
1.3 Literals
There are literals for boolean, integer, floating point, string, and null in an eval-
expression.
■ Boolean - true and false
■ Integer - As defined by the IntegerLiteral construct in Section 1.19
■ Floating point - As defined by the FloatingPointLiteral construct in
Section 1.19
■ String - With single and double quotes - "is escaped as\", ' is escaped as\',
and\is escaped as\\. Quotes only need to be escaped in a string value enclosed
in the same type of quote
■ Null - null
 
+-*などのオペレータの演算規則も規定されています.
1.3 Literals
There are literals for boolean, integer, floating point, string, and null in an eval-expression.
  ■ Boolean - true and false
  ■ Integer - As defined by the IntegerLiteral construct in Section 1.19
  ■ Floating point - As defined by the FloatingPointLiteral construct in
Section 1.19
  ■ String - With single and double quotes - " is escaped as \", ' is escaped as \',and \ is escaped as \\. Quotes only need to be escaped in a string value enclosed in the same type of quote
  ■ Null - null
  ■ If operator is -, return A.subtract(B)
  ■ If operator is *, return A.multiply(B)
  ■ If A or B is a Float, Double,or String containing ., e,or E:
  ■ If A or B is BigInteger, coerce both A and B to BigDecimal and apply operator.
  ■ Otherwise, coerce both A and B to Double and apply operator
  ■ If A or B is BigInteger, coerce both to BigInteger and then:
  ■ If operator is +, return A.add(B)
  ■ If operator is -, return A.subtract(B)
  ■ If operator is *, return A.multiply(B)
  ■ Otherwise coerce both A and B to Long and apply operator
  ■ If operator results in exception, error

Integer型のように、先に紹介したIntegerLiteralに直接渡します.
 
すなわち、仕様ではこれらが仕様されていますが、javaのもののように、仕様が規定されています(ソート時にreturn a-bを使用する人が多い場合、aが負数であればオーバーフローする可能性があります)が、エラーが発生しやすいです.