Можете ли вы заставить TextField ‹BigDecimal› принимать и, и. как десятичный разделитель?

В приложении Wicket у меня есть текстовое поле с десятичным числом:

 TextField<BigDecimal> f = 
     new TextField<BigDecimal>("f", new PropertyModel<BigDecimal>(model, "share"));

Я хочу, чтобы он всегда принимал и то, и другое. (точка) и (запятая) в качестве десятичного разделителя (независимо от языковых настроек браузера).

Для отображения значения используется локаль сеанса [которая в нашем случае должна быть "fi" (-> запятая)], но здесь меня интересует, что поле принимает < / em> в качестве ввода.

У меня вопрос: нужно ли менять поле на TextField<String> и вручную преобразовывать в тип объекта домена (BigDecimal)? Или есть какой-то способ использовать TextField<BigDecimal> (который позволяет, например, использовать MinimumValidator или RangeValidator Wicket) и по-прежнему принимать оба десятичных разделителя?


person Jonik    schedule 11.07.2011    source источник
comment
У меня сейчас нет документации, но вы можете зарегистрировать конвертеры глобально в своем классе приложения. Таким образом, вы можете зарегистрировать свою собственную реализацию конвертера для BigDecimal и принять там оба варианта.   -  person bert    schedule 11.07.2011
comment
@bert, спасибо! Прочитав Wicket in Action (стр. 163), это действительно может быть лучший способ приблизиться к этому ... Рассмотрите возможность написания этого в качестве ответа.   -  person Jonik    schedule 11.07.2011
comment
Небольшое предупреждение: в некоторых регионах оба символа могут встречаться в одном и том же числе, т.е. . используется для группировки тысяч и , в качестве десятичного разделителя. Если вам нужен универсальный анализатор чисел, убедитесь, что ваш код может обрабатывать числа типа 32.519.100,28.   -  person biziclop    schedule 11.07.2011
comment
@biziclop: Да, хорошее замечание. (В нашем случае нам не нужно универсальное решение, поэтому мы можем обойтись чем-нибудь попроще, например тем, что я опубликовал в качестве ответа.)   -  person Jonik    schedule 11.07.2011


Ответы (1)


Благодаря комментарию @bert и книге Wicket in Action я нашел подход, который работает. В классе Application укажите настраиваемый конвертер для BigDecimals:

@Override
protected IConverterLocator newConverterLocator() {
    ConverterLocator converterLocator = new ConverterLocator();
    converterLocator.set(BigDecimal.class, new CustomBigDecimalConverter());
    return converterLocator;
}

А в настраиваемом конвертере convertToObject нужно переопределить. NB: этого достаточно для наших нужд; подумайте о своих требованиях и при необходимости адаптируйте!

public class CustomBigDecimalConverter extends BigDecimalConverter {

    @Override
    public BigDecimal convertToObject(String value, Locale locale) {
        // NB: this isn't universal & your mileage problably varies!
        // (Specifically, this breaks if '.' is used as thousands separator)
        if ("fi".equals(locale.getLanguage())) {
            value = value.replace('.', ',');
        }
        return super.convertToObject(value, locale);
    }
}

Изменить: оффтоп, но я тоже хочу это задокументировать. Нам нужно было, чтобы наше приложение поддерживало шкалу с четырьмя десятичными знаками, и наш специальный конвертер BigDecimal прекрасно решает и эту проблему.

  @Override
    public String convertToString(Object value, Locale locale) {
        NumberFormat fmt = getNumberFormat(locale);
        fmt.setMaximumFractionDigits(4); // By default this is 3.
        return fmt.format(value);
    }

После этой настройки десятичное число, например 2.0005, будет отображаться как 2.0005 вместо 2.

person Jonik    schedule 11.07.2011