[TEEDA-377] @NumberLengthにてDecimal型のチェックが行われない Created: 2007-09-18  Updated: 2007-09-19  Resolved: 2007-09-19

Status: Resolved
Project: Teeda
Component/s: Teeda Extension
Affects Version/s: None
Fix Version/s: 1.0.11

Type: Bug Priority: Major
Reporter: Shinichi Yanagisawa Assignee: shot
Resolution: Fixed Votes: 0
Labels: None
Environment:

Windows Vista / jdk1.6.0_02



 Description   

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



 Comments   
Comment by koichik [ 2007-09-19 ]

To: Yanagisawa さん

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

Comment by shot [ 2007-09-19 ]

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

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

Comment by shot [ 2007-09-19 ]

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

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

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

Comment by Shinichi Yanagisawa [ 2007-09-19 ]

実は意図して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を利用するものとしては正しく記述しているつもりでもそれが内部で無視されてしまい、原因不明の状態に陥るのはいただけないですね。なんらかの方法でそれは誤った使い方だと利用者に判るようにして欲しいです。

Comment by koichik [ 2007-09-19 ]

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();
  }
}
Comment by Shinichi Yanagisawa [ 2007-09-18 ]

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

Comment by koichik [ 2007-09-18 ]

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

Comment by Anonymous [ 2007-09-18 ]

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

Comment by shot [ 2007-09-18 ]

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;
    }

Generated at Fri Apr 26 23:54:36 JST 2024 using Jira 9.15.0#9150000-sha1:9ead8528714127d8cfabf2446010d7e62c0a195c.