Синтаксический анализ BigDecimal локали - несоответствие между BigDecimalConverter Wicket и java.math.BigDecimal - PullRequest
1 голос
/ 04 ноября 2011

Когда дело доходит до разбора чисел с десятичными разделителями из строки, BigDecimalConverter Wicket ведет себя иначе, чем конструктор BigDecimal (String val).

Давайте попробуем разобрать число с запятой в качестве десятичного разделителя, используя локали США. (Я использую Wicket 1.4.14 BTW.)


new BigDecimalConverter().convertToObject("1,3", Locale.US)
возвращает 13,


но


Locale.setDefault(Locale.US);
new BigDecimal("1,3")  

бросков NumberFormatException.


Почему в этом случае BigDecimalConverter не ведет себя так же, как BigDecimal? Число "1,3" не имеет смысла для США.

1 Ответ

6 голосов
/ 04 ноября 2011

Класс BigDecimal реализует свой собственный алгоритм проверки на входе, который выбрасывает NumberFormatException.

Причина, по которой BigDecimalConverter анализирует 1,3 как 13, заключается в том, что он использует необработанный DecimalFormat за кадром. В AbstractNumberConverter.parse() комбинация методов getNumberFormat(locale) и parse() сводится к следующему фрагменту, который выводит Wicket из уравнения:

NumberFormat format = NumberFormat.getInstance(Locale.US);
format.setParseBigDecimal(true);
BigDecimal bd = format.parseObject("1,3");
System.out.println(bd.toString()); // Prints 13 !

UPDATE Причина, по которой DecimalFormat игнорирует символ ,, заключается в том, что он определен как разделитель группировки в DecimalFormatSymbols для локали США. Это разрешено и законно, как это было бы в 1,300.5.

Если вы хотите избежать преобразования 1,3 в 13 и вызвать исключение недопустимого преобразования формата, вы можете переопределить BigDecimalConverter.getNumberFormat(Locale), чтобы изменить DecimalFormat, чтобы не использовать группировку, используйте другой символ группировки или используйте более строгий шаблон. Например:

TextField<BigDecimal> text = new TextField<BigDecimal>(id, model){
    @Override
    public IConverter getConverter(Class<?> type) {
        return new BigDecimalConverter() {
            @Override
            public NumberFormat getNumberFormat(Locale locale) {
                NumberFormat format = super.getNumberFormat(locale);
                format.setGroupingUsed(false);
                return format;
            }
        };
    }
};
text.setType(BigDecimal.class);

Примечание : используйте приведенный выше пример с осторожностью, создайте класс для Converter, чтобы он не создавался при каждом вызове getConverter(), и не изменяйте экземпляр NumberFormat BigDecimalConverter.getNumberFormat() возвращает, это может быть глобальный общий экземпляр.

Просто добавьте, это точный фрагмент кода, который игнорирует символ ,, являющийся разделителем групп: DecimalFormat.subparse() ветвь в строке 1522 . При вводе 1,3 запятая игнорируется, а isGroupingUsed() true.

...