Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you make a TextField<BigDecimal> accept both , and . as decimal separator?

In a Wicket app, I have a decimal number text field:

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

I want it to always accept both . (dot) and , (comma) as decimal separator (regardless of browser's locale settings).

For showing the value, session's locale is used [which in our case is forced to be "fi" (-> comma)], but here I'm interested in what the field accepts as input.

My question is, do I have to change the field to TextField<String>, and convert to domain object's type (BigDecimal) manually? Or is there some way to use TextField<BigDecimal> (which allows e.g. making use of Wicket's MinimumValidator or RangeValidator), and still have it accept both decimal separators?

like image 266
Jonik Avatar asked Jul 11 '11 09:07

Jonik


People also ask

How do you change the decimal separator in Java?

Use String.format("%. 2f", d); This method uses our JVM's default Locale to choose the decimal separator.

What is decimal Number format?

DecimalFormat is a concrete subclass of NumberFormat that formats decimal numbers. It has a variety of features designed to make it possible to parse and format numbers in any locale, including support for Western, Arabic, and Indic digits.


1 Answers

Thanks to @bert's comment, and the Wicket in Action book, I found an approach that works. In the Application class specify a custom converter for BigDecimals:

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

And in the custom converter, convertToObject needs to be overridden. NB: this is sufficient for our needs; think about your requirements and adapt as needed!

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

Edit: Offtopic, but I want to document this too. We needed our app to support a scale of 4 decimal places, and our custom BigDecimal converter nicely solves that problem too.

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

After this customisation, a decimal number like 2.0005 will be shown as 2.0005 instead of 2.

like image 156
Jonik Avatar answered Sep 25 '22 15:09

Jonik