in trinidad-api/src/main/java/org/apache/myfaces/trinidad/convert/NumberConverter.java [187:342]
public Object getAsObject(
FacesContext context,
UIComponent component,
String value)
{
if (null == context || null == component)
{
throw new NullPointerException(_LOG.getMessage(
"NULL_FACESCONTEXT_OR_UICOMPONENT"));
}
if (null == value)
return null;
if (isDisabled())
return value;
value = value.trim();
if (value.length() < 1)
return null;
String pattern = getPattern();
String type = getType();
int typeIdx = _getType(pattern, type);
if (null == pattern && null == type)
{
throw new IllegalArgumentException(_LOG.getMessage(
"EITHER_PATTERN_OR_TYPE_MUST_SPECIFIED"));
}
RequestContext reqCtx = RequestContext.getCurrentInstance();
Locale locale = _getLocale(reqCtx, context);
NumberFormat fmt = _getNumberFormat(pattern, type, locale, reqCtx);
DecimalFormat df = (DecimalFormat)fmt;
if(typeIdx == _CURRENCY_TYPE)
{
// Setup custom currency code/symbol if any
_setCurrencyFormattingProperties(reqCtx, fmt);
}
_setFormatProperties(fmt, typeIdx, reqCtx);
df.setParseBigDecimal(true); // TODO What does this do?
DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
if("currency".equals(type))
{
// Setup custom currency code/symbol if any
_setCurrencyFormattingProperties(reqCtx, fmt);
}
// We change the grouping_separator b/c TRINIDAD-849
// source is this JDK bug: 4510618.
boolean changed = false;
if (dfs.getGroupingSeparator() == '\u00a0')
{
// In some locales, such as fr_FR, the grouping separator is '\u00a0', a
// non-breaking space. However, users will normally enter a regular space
// character into an input field, so in order for the input to be parsed
// correctly, we set the grouping separator to a regular space character.
dfs.setGroupingSeparator(' ');
df.setDecimalFormatSymbols(dfs);
// In the (rare) case that the user actually enters a non-breaking space,
// we replace it with a regular space. This should be fine, since the
// percent format for fr_FR is " %" (regular space followed by percent).
value = value.replace('\u00a0', ' ');
changed = true;
}
ParsePosition pp = new ParsePosition(0);
Number num = (Number)fmt.parseObject(value, pp);
// The following determines whether the percent/currency symbol was left off.
if (num == null && (typeIdx == _CURRENCY_TYPE || typeIdx == _PERCENT_TYPE))
{
// For parsing 'value' as a Number when the percent/currency symbol is left off.
NumberFormat nfmt = NumberFormat.getNumberInstance(locale);
DecimalFormat ndf = (DecimalFormat)nfmt;
ndf.setParseBigDecimal(true); // TODO What does this do?
DecimalFormatSymbols ndfs = null;
if (changed)
{
ndfs = ndf.getDecimalFormatSymbols();
ndfs.setGroupingSeparator(' ');
ndf.setDecimalFormatSymbols(ndfs);
}
// Assume the percent/currency symbol was left off, in which case we should
// be able to parse 'value' as a Number.
// An error occured, so the index of pp should still be 0.
num = (Number)nfmt.parseObject(value, pp);
if (typeIdx == _PERCENT_TYPE && num != null)
num = num.doubleValue() / 100.0;
}
// Change it back, since we could have been handed a cached reference. This
// may not be thread-safe, but it probably doesn't have to be.
if (changed)
{
dfs.setGroupingSeparator('\u00a0');
df.setDecimalFormatSymbols(dfs);
}
if (pp.getIndex() != value.length())
{
// According to the comments in
// trinidad-api\src\main\xrts\org\apache\myfaces\trinidad\resource\MessageBundle.xrts,
// the substitution parameters are supposed to be:
// {0} the label that identifies the component
// {1} value entered by the user
Object label = ConverterUtils.getComponentLabel(component);
Object[] params = null;
if (typeIdx == _PATTERN_TYPE)
{
// We call this since the pattern may contain the generic currency sign, which we don't
// want to display to the user.
pattern = getLocalizedPattern(context, pattern, dfs);
params = new Object[] {label, value, pattern};
}
else if (typeIdx == _NUMBER_TYPE)
{
params = new Object[] {label, value};
}
else if (typeIdx == _CURRENCY_TYPE)
{
params = new Object[] {label, value, fmt.format(_EXAMPLE_CURRENCY)};
}
else if (typeIdx == _PERCENT_TYPE)
{
params = new Object[] {label, value, fmt.format(_EXAMPLE_PERCENT)};
}
throw new ConverterException(
getConvertMessage(context, component, value, params));
}
// if we set setParseIntegerOnly(isIntegerOnly()) - This may result in
// the formatter stopping to parse after the first decimal point.
// that is number of value 222.22 which is legitimate, hence our test would
// fail. hence we did not do the following
// fmt.setParseIntegerOnly(isIntegerOnly());
// We allow the value to be totally parsed and if the user has set
// to integer only. We will return the long value from the number object
// we have in hand.
if (isIntegerOnly())
return Long.valueOf(num.longValue());
return num;
}