public Object getAsObject()

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