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?
Use String.format("%. 2f", d); This method uses our JVM's default Locale to choose the decimal separator.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With