• Type: Bug
    • Resolution: Fixed
    • Priority: Major
    • 1.0.11
    • Affects Version/s: None
    • Component/s: Teeda Extension
    • None
    • Environment:
      Windows Vista / jdk1.6.0_02

      Decimal型のフィールド(小数点あり)に対しNumberLengthValidatorにてチェックを行おうとしたところ、チェックが行われない。
      TnumberLengthValidator の getDigits メソッドにて、パラメタvalue のタイプがDecimalの場合の対応を行っていないのが原因と思われる。

          [TEEDA-377] @NumberLengthにてDecimal型のチェックが行われない

          koichik added a comment -

          To: Yanagisawa さん

          TEEDA-378 も同様ですが,そういう場合は問題となっている状況自体を書いていただいた方がいいです.
          今回の場合は,「teeda-html-example の add/addExt.html で小数点以下に 3 桁以上入力してもエラーにならない」などであれば,より円滑に状況が伝わったと思います.
          問題と同時に原因や解決策を書き添えていただくのは構わないのですが,原因 (の推測) と解決策 (の案) だけでは問題を理解することができません.
          またご報告いただける際にはその点を考慮してください.よろしくお願いします.

          koichik added a comment - To: Yanagisawa さん TEEDA-378 も同様ですが,そういう場合は問題となっている状況自体を書いていただいた方がいいです. 今回の場合は,「teeda-html-example の add/addExt.html で小数点以下に 3 桁以上入力してもエラーにならない」などであれば,より円滑に状況が伝わったと思います. 問題と同時に原因や解決策を書き添えていただくのは構わないのですが,原因 (の推測) と解決策 (の案) だけでは問題を理解することができません. またご報告いただける際にはその点を考慮してください.よろしくお願いします.

          shot added a comment -

          Rev.3594にて修正しました.

          Double型のプロパティでTNumberLengthValidatorを指定している場合、
          明示的に例外をとばすようにしました.
          (TNumberLengthValidatorがInteger、Long、BigDecimalしか扱えないため)

          shot added a comment - Rev.3594にて修正しました. Double型のプロパティでTNumberLengthValidatorを指定している場合、 明示的に例外をとばすようにしました. (TNumberLengthValidatorがInteger、Long、BigDecimalしか扱えないため)

          shot added a comment -

          NumberConverterというか、DecimalFormatSymbols/DecimalFormatを使ったとしても
          JDK1.4ではNumberFormatがDoubleかLongしか返せないのです.

          というわけで、サンプルが適切でないのは修正しておきます.
          代わりに@BigDecimalを使ってください.

          TNumberLengthValidatorでDoubleが指定されているときは例外飛ばすようにしておきます.
          >正しく記述しているつもりでもそれが内部で無視されてしまい、原因不明の状態に陥るのはいただけない

          shot added a comment - NumberConverterというか、DecimalFormatSymbols/DecimalFormatを使ったとしても JDK1.4ではNumberFormatがDoubleかLongしか返せないのです. というわけで、サンプルが適切でないのは修正しておきます. 代わりに@BigDecimalを使ってください. TNumberLengthValidatorでDoubleが指定されているときは例外飛ばすようにしておきます. >正しく記述しているつもりでもそれが内部で無視されてしまい、原因不明の状態に陥るのはいただけない

          実は意図してDoubleを使った訳ではありません。
          私はTeedaの初心者ですが、Teedaを理解するためにteeda-html-exampleを試していたのですが、
          その中の「6.足し算による入力サンプル(金額入力系コンポーネント)」(AddExtPage.java)では、下記のようにコーディングされていました。
          @NumberConverter(pattern = "#.0000", type = "currency")
          @NumberLength(integralMax = 12, fractionMax = 2)
          @GreaterThanConstant
          private BigDecimal arg1;
          arg1に小数点3桁以上の数値(例えば(「1000.111」)を入力すれば当然エラーになると思ったところなぜかエラーになりませんでした。なぜだろうとコードを追って行ったところ、@NumberConverterはDoubleで返却されるようになっており、@NumberLengthでは上述したようにDoubleをサポートしていないためチェックが行われていないということが判り、今回コメントを記述しました。
          おっしゃる通りDouble型では少数部の表現が正確ではないため@NunberLengthで少数部をチェックするのは不適当ですね。ただTeedaを利用するものとしては正しく記述しているつもりでもそれが内部で無視されてしまい、原因不明の状態に陥るのはいただけないですね。なんらかの方法でそれは誤った使い方だと利用者に判るようにして欲しいです。

          Shinichi Yanagisawa added a comment - 実は意図してDoubleを使った訳ではありません。 私はTeedaの初心者ですが、Teedaを理解するためにteeda-html-exampleを試していたのですが、 その中の「6.足し算による入力サンプル(金額入力系コンポーネント)」(AddExtPage.java)では、下記のようにコーディングされていました。 @NumberConverter(pattern = "#.0000", type = "currency") @NumberLength(integralMax = 12, fractionMax = 2) @GreaterThanConstant private BigDecimal arg1; arg1に小数点3桁以上の数値(例えば(「1000.111」)を入力すれば当然エラーになると思ったところなぜかエラーになりませんでした。なぜだろうとコードを追って行ったところ、@NumberConverterはDoubleで返却されるようになっており、@NumberLengthでは上述したようにDoubleをサポートしていないためチェックが行われていないということが判り、今回コメントを記述しました。 おっしゃる通りDouble型では少数部の表現が正確ではないため@NunberLengthで少数部をチェックするのは不適当ですね。ただTeedaを利用するものとしては正しく記述しているつもりでもそれが内部で無視されてしまい、原因不明の状態に陥るのはいただけないですね。なんらかの方法でそれは誤った使い方だと利用者に判るようにして欲しいです。

          koichik added a comment -

          Double に NumberLengthValidator?
          そういうことがしたいなら Double ではなく BigDecimal を使うべきだと思いますが.

          そもそも Double (double) の長さとは?
          例えば 1.23E45 はどのようにバリデーションすべきでしょうか?
          仮数部・指数部ではなく,整数部・小数部の長さでバリデートするのでしょうか?
          あるいは,0.1 のように正確に表現できない値の場合はどうすべきでしょうか? 適当に丸めるべきですか?
          それらの仕様は Teeda としてサポートする必要があるほど一般的でしょうか?

          それよりは,以下のようにした方がいいのでは?

          public class HogePage {
            @NumberLength(...)
            public BigDecimal foo;
          
            public Double getFooAsDouble() {
              return foo == null ? null ? foo.doubleValue();
            }
          }
          

          koichik added a comment - Double に NumberLengthValidator? そういうことがしたいなら Double ではなく BigDecimal を使うべきだと思いますが. そもそも Double (double) の長さとは? 例えば 1.23E45 はどのようにバリデーションすべきでしょうか? 仮数部・指数部ではなく,整数部・小数部の長さでバリデートするのでしょうか? あるいは,0.1 のように正確に表現できない値の場合はどうすべきでしょうか? 適当に丸めるべきですか? それらの仕様は Teeda としてサポートする必要があるほど一般的でしょうか? それよりは,以下のようにした方がいいのでは? public class HogePage { @NumberLength(...) public BigDecimal foo; public Double getFooAsDouble() { return foo == null ? null ? foo.doubleValue(); } }

          すみません。Double型の間違いでした。
          今までのコメントについて、Decimal型をDouble型に読み替えてください。

          Shinichi Yanagisawa added a comment - すみません。Double型の間違いでした。 今までのコメントについて、Decimal型をDouble型に読み替えてください。

          koichik added a comment -

          BigDecimal ではない Decimal とは? FQN で書いてください.
          BigInteger は整数 (小数点以下がない) なので該当しませんよね.

          koichik added a comment - BigDecimal ではない Decimal とは? FQN で書いてください. BigInteger は整数 (小数点以下がない) なので該当しませんよね.

          Anonymous added a comment -

          value が Decimal型(BigDecimalではない) の場合、getDigitsメソッドにて判定をしていない( value instanceof Decimalの条件文がない)ため、digitsのintegral, fractionの値がゼロのままリターンしてしまう。結果、TNumberLengthValidator.validateメソッドでチェックエラーとならない。

          Anonymous added a comment - value が Decimal型(BigDecimalではない) の場合、getDigitsメソッドにて判定をしていない( value instanceof Decimalの条件文がない)ため、digitsのintegral, fractionの値がゼロのままリターンしてしまう。結果、TNumberLengthValidator.validateメソッドでチェックエラーとならない。

          shot added a comment -

          TNumberLengthValidator.getDigits()で下記のように対応しています.
          もう少し具体例をお願いします.

              protected Digits getDigits(final FacesContext context, final Object value) {
                  final Digits digits = new Digits();
                  if (value instanceof Integer) {
                      final Integer num = (Integer) value;
                      final int abs = Math.abs(num.intValue());
                      digits.setIntegral(String.valueOf(abs).length());
                  } else if (value instanceof Long) {
                      final Long num = (Long) value;
                      final long abs = Math.abs(num.longValue());
                      digits.setIntegral(String.valueOf(abs).length());
                  } else if (value instanceof BigDecimal) {
                      BigDecimal num = (BigDecimal) value;
                      if (num.compareTo(ZERO) < 0) {
                          num = num.negate();
                      }
                      final String s = num.toString();
                      final Locale locale = context.getViewRoot().getLocale();
                      final String decimalSeparator = NumberConversionUtil
                              .findDecimalSeparator(locale);
                      final int pos = s.indexOf(decimalSeparator);
                      if (-1 < pos) {
                          digits.setIntegral(s.substring(0, pos).length());
                          digits.setFraction(s.substring(pos + 1).length());
                      } else {
                          digits.setIntegral(s.length());
                      }
                  }
                  return digits;
              }
          
          

          shot added a comment - TNumberLengthValidator.getDigits()で下記のように対応しています. もう少し具体例をお願いします. protected Digits getDigits( final FacesContext context, final Object value) { final Digits digits = new Digits(); if (value instanceof Integer ) { final Integer num = ( Integer ) value; final int abs = Math .abs(num.intValue()); digits.setIntegral( String .valueOf(abs).length()); } else if (value instanceof Long ) { final Long num = ( Long ) value; final long abs = Math .abs(num.longValue()); digits.setIntegral( String .valueOf(abs).length()); } else if (value instanceof BigDecimal) { BigDecimal num = (BigDecimal) value; if (num.compareTo(ZERO) < 0) { num = num.negate(); } final String s = num.toString(); final Locale locale = context.getViewRoot().getLocale(); final String decimalSeparator = NumberConversionUtil .findDecimalSeparator(locale); final int pos = s.indexOf(decimalSeparator); if (-1 < pos) { digits.setIntegral(s.substring(0, pos).length()); digits.setFraction(s.substring(pos + 1).length()); } else { digits.setIntegral(s.length()); } } return digits; }

            Assignee:
            shot
            Reporter:
            Shinichi Yanagisawa
            Votes:
            0 Vote for this issue
            Watchers:
            Start watching this issue

              Created:
              Updated:
              Resolved: