Coverage Report - javax.faces.convert.NumberConverter
 
Classes in this File Line Coverage Branch Coverage Complexity
NumberConverter
0%
0/186
0%
0/123
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package javax.faces.convert;
 20  
 
 21  
 import java.text.DecimalFormat;
 22  
 import java.text.DecimalFormatSymbols;
 23  
 import java.text.NumberFormat;
 24  
 import java.text.ParseException;
 25  
 import java.util.Currency;
 26  
 import java.util.Locale;
 27  
 
 28  
 import javax.faces.component.StateHolder;
 29  
 import javax.faces.component.UIComponent;
 30  
 import javax.faces.context.FacesContext;
 31  
 
 32  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
 33  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
 34  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
 35  
 
 36  
 /**
 37  
  * This tag creates a number formatting converter and associates it
 38  
  * with the nearest parent UIComponent.
 39  
  * 
 40  
  * Unless otherwise specified, all attributes accept static values or EL expressions.
 41  
  * 
 42  
  * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
 43  
  *
 44  
  * @author Thomas Spiegl (latest modification by $Author: lu4242 $)
 45  
  * @version $Revision: 693358 $ $Date: 2008-09-08 22:54:29 -0500 (Mon, 08 Sep 2008) $
 46  
  */
 47  
 @JSFConverter(
 48  
     name="f:convertNumber",
 49  
     bodyContent="empty",
 50  
     tagClass="org.apache.myfaces.taglib.core.ConvertNumberTag")
 51  
 @JSFJspProperty(
 52  
     name="binding", 
 53  
     returnType = "javax.faces.convert.NumberConverter",
 54  
     longDesc = "A ValueExpression that evaluates to a NumberConverter.")
 55  
 public class NumberConverter
 56  
         implements Converter, StateHolder
 57  
 {
 58  
     // API FIELDS
 59  
     public static final String CONVERTER_ID = "javax.faces.Number";
 60  
     public static final String STRING_ID = "javax.faces.converter.STRING";
 61  
     public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY";
 62  
     public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER";
 63  
     public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN";
 64  
     public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT";
 65  
 
 66  
     private static final boolean JAVA_VERSION_14;
 67  
 
 68  
     static
 69  
     {
 70  0
         JAVA_VERSION_14 = checkJavaVersion14();
 71  0
     }
 72  
 
 73  
     private String _currencyCode;
 74  
     private String _currencySymbol;
 75  
     private Locale _locale;
 76  
     private int _maxFractionDigits;
 77  
     private int _maxIntegerDigits;
 78  
     private int _minFractionDigits;
 79  
     private int _minIntegerDigits;
 80  
     private String _pattern;
 81  0
     private String _type = "number";
 82  0
     private boolean _groupingUsed = true;
 83  0
     private boolean _integerOnly = false;
 84  
     private boolean _transient;
 85  
 
 86  
     private boolean _maxFractionDigitsSet;
 87  
     private boolean _maxIntegerDigitsSet;
 88  
     private boolean _minFractionDigitsSet;
 89  
     private boolean _minIntegerDigitsSet;
 90  
 
 91  
 
 92  
     // CONSTRUCTORS
 93  
     public NumberConverter()
 94  0
     {
 95  0
     }
 96  
 
 97  
     // METHODS
 98  
     public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
 99  
     {
 100  0
         if (facesContext == null) throw new NullPointerException("facesContext");
 101  0
         if (uiComponent == null) throw new NullPointerException("uiComponent");
 102  
 
 103  0
         if (value != null)
 104  
         {
 105  0
             value = value.trim();
 106  0
             if (value.length() > 0)
 107  
             {
 108  0
                 NumberFormat format = getNumberFormat(facesContext);
 109  0
                 format.setParseIntegerOnly(_integerOnly);
 110  
                 
 111  0
                 DecimalFormat df = (DecimalFormat)format;
 112  
                 //df.setParseBigDecimal(true);
 113  0
                 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
 114  0
                 boolean changed = false;
 115  0
                 if(dfs.getGroupingSeparator() == '\u00a0')
 116  
                 {
 117  0
                   dfs.setGroupingSeparator(' ');
 118  0
                   df.setDecimalFormatSymbols(dfs);
 119  0
                   changed = true;
 120  
                 }
 121  
                 try
 122  
                 {
 123  0
                     return format.parse(value);
 124  
                 }
 125  0
                 catch (ParseException e)
 126  
                 {
 127  0
                   if(changed)
 128  
                   {
 129  0
                     dfs.setGroupingSeparator('\u00a0');
 130  0
                     df.setDecimalFormatSymbols(dfs);
 131  
                   }
 132  
                   try
 133  
                   {
 134  0
                     return format.parse(value);
 135  
                   }
 136  0
                   catch (ParseException pe)
 137  
                   {
 138  
 
 139  0
                     if(getPattern() != null)
 140  0
                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
 141  
                                                                                     PATTERN_ID,
 142  
                                                                                     new Object[]{value,"$###,###",_MessageUtils.getLabel(facesContext, uiComponent)}));
 143  0
                     else if(getType().equals("number"))
 144  0
                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
 145  
                                                                                     NUMBER_ID,
 146  
                                                                                     new Object[]{value,"21",_MessageUtils.getLabel(facesContext, uiComponent)}));
 147  0
                     else if(getType().equals("currency"))
 148  0
                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
 149  
                                                                                     CURRENCY_ID,
 150  
                                                                                     new Object[]{value,"42.25",_MessageUtils.getLabel(facesContext, uiComponent)}));
 151  0
                     else if(getType().equals("percent"))
 152  0
                         throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
 153  
                                                                                     PERCENT_ID,
 154  
                                                                                     new Object[]{value,".90",_MessageUtils.getLabel(facesContext, uiComponent)}));
 155  
                   }
 156  
                 }
 157  
             }
 158  
         }
 159  0
         return null;
 160  
     }
 161  
 
 162  
     public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
 163  
     {
 164  0
         if (facesContext == null) throw new NullPointerException("facesContext");
 165  0
         if (uiComponent == null) throw new NullPointerException("uiComponent");
 166  
 
 167  0
         if (value == null)
 168  
         {
 169  0
             return "";
 170  
         }
 171  0
         if (value instanceof String)
 172  
         {
 173  0
             return (String)value;
 174  
         }
 175  
 
 176  0
         NumberFormat format = getNumberFormat(facesContext);
 177  0
         format.setGroupingUsed(_groupingUsed);
 178  0
         if (_maxFractionDigitsSet) format.setMaximumFractionDigits(_maxFractionDigits);
 179  0
         if (_maxIntegerDigitsSet) format.setMaximumIntegerDigits(_maxIntegerDigits);
 180  0
         if (_minFractionDigitsSet) format.setMinimumFractionDigits(_minFractionDigits);
 181  0
         if (_minIntegerDigitsSet) format.setMinimumIntegerDigits(_minIntegerDigits);
 182  0
         formatCurrency(format);
 183  
         try
 184  
         {
 185  0
             return format.format(value);
 186  
         }
 187  0
         catch (Exception e)
 188  
         {
 189  0
             throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, STRING_ID, new Object[]{value,_MessageUtils.getLabel(facesContext, uiComponent)}),e);
 190  
         }
 191  
     }
 192  
 
 193  
     private NumberFormat getNumberFormat(FacesContext facesContext)
 194  
     {
 195  0
         Locale locale = _locale != null ? _locale : facesContext.getViewRoot().getLocale();
 196  
 
 197  0
         if (_pattern == null && _type == null)
 198  
         {
 199  0
             throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
 200  
         }
 201  
 
 202  
         // pattern
 203  0
         if (_pattern != null)
 204  
         {
 205  0
             return new DecimalFormat(_pattern, new DecimalFormatSymbols(locale));
 206  
         }
 207  
 
 208  
         // type
 209  0
         if (_type.equals("number"))
 210  
         {
 211  0
             return NumberFormat.getNumberInstance(locale);
 212  
         }
 213  0
         else if (_type.equals("currency"))
 214  
         {
 215  0
             return NumberFormat.getCurrencyInstance(locale);
 216  
         }
 217  0
         else if (_type.equals("percent"))
 218  
         {
 219  0
             return NumberFormat.getPercentInstance(locale);
 220  
         }
 221  0
         throw new ConverterException("Cannot get NumberFormat, illegal type " + _type);
 222  
     }
 223  
 
 224  
     private void formatCurrency(NumberFormat format)
 225  
     {
 226  0
         if (_currencyCode == null && _currencySymbol == null)
 227  
         {
 228  0
             return;
 229  
         }
 230  
 
 231  
         boolean useCurrencyCode;
 232  0
         if (JAVA_VERSION_14)
 233  
         {
 234  0
             useCurrencyCode = _currencyCode != null;
 235  
         }
 236  
         else
 237  
         {
 238  0
             useCurrencyCode = _currencySymbol == null;
 239  
         }
 240  
 
 241  0
         if (useCurrencyCode)
 242  
         {
 243  
             // set Currency
 244  
             try
 245  
             {
 246  0
                 format.setCurrency(Currency.getInstance(_currencyCode));
 247  
             }
 248  0
             catch (Exception e)
 249  
             {
 250  0
                 throw new ConverterException("Unable to get Currency instance for currencyCode " +
 251  
                                              _currencyCode);
 252  0
             }
 253  
         }
 254  0
         else if (format instanceof DecimalFormat)
 255  
 
 256  
         {
 257  0
             DecimalFormat dFormat = (DecimalFormat)format;
 258  0
             DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
 259  0
             symbols.setCurrencySymbol(_currencySymbol);
 260  0
             dFormat.setDecimalFormatSymbols(symbols);
 261  
         }
 262  0
     }
 263  
 
 264  
     // STATE SAVE/RESTORE
 265  
     public void restoreState(FacesContext facesContext, Object state)
 266  
     {
 267  0
         Object values[] = (Object[])state;
 268  0
         _currencyCode = (String)values[0];
 269  0
         _currencySymbol = (String)values[1];
 270  0
         _locale = (Locale)values[2];
 271  0
         Integer value = (Integer)values[3];
 272  0
         _maxFractionDigits = value != null ? value.intValue() : 0;
 273  0
         value = (Integer)values[4];
 274  0
         _maxIntegerDigits = value != null ? value.intValue() : 0;
 275  0
         value = (Integer)values[5];
 276  0
         _minFractionDigits = value != null ? value.intValue() : 0;
 277  0
         value = (Integer)values[6];
 278  0
         _minIntegerDigits = value != null ? value.intValue() : 0;
 279  0
         _pattern = (String)values[7];
 280  0
         _type = (String)values[8];
 281  0
         _groupingUsed = ((Boolean)values[9]).booleanValue();
 282  0
         _integerOnly = ((Boolean)values[10]).booleanValue();
 283  0
         _maxFractionDigitsSet = ((Boolean)values[11]).booleanValue();
 284  0
         _maxIntegerDigitsSet = ((Boolean)values[12]).booleanValue();
 285  0
         _minFractionDigitsSet = ((Boolean)values[13]).booleanValue();
 286  0
         _minIntegerDigitsSet = ((Boolean)values[14]).booleanValue();
 287  0
     }
 288  
 
 289  
     public Object saveState(FacesContext facesContext)
 290  
     {
 291  0
         Object values[] = new Object[15];
 292  0
         values[0] = _currencyCode;
 293  0
         values[1] = _currencySymbol;
 294  0
         values[2] = _locale;
 295  0
         values[3] = _maxFractionDigitsSet ? new Integer(_maxFractionDigits) : null;
 296  0
         values[4] = _maxIntegerDigitsSet ? new Integer(_maxIntegerDigits) : null;
 297  0
         values[5] = _minFractionDigitsSet ? new Integer(_minFractionDigits) : null;
 298  0
         values[6] = _minIntegerDigitsSet ? new Integer(_minIntegerDigits) : null;
 299  0
         values[7] = _pattern;
 300  0
         values[8] = _type;
 301  0
         values[9] = _groupingUsed ? Boolean.TRUE : Boolean.FALSE;
 302  0
         values[10] = _integerOnly ? Boolean.TRUE : Boolean.FALSE;
 303  0
         values[11] = _maxFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
 304  0
         values[12] = _maxIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
 305  0
         values[13] = _minFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
 306  0
         values[14] = _minIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
 307  0
         return values;
 308  
     }
 309  
 
 310  
     // GETTER & SETTER
 311  
     
 312  
     /**
 313  
      * ISO 4217 currency code
 314  
      * 
 315  
      */
 316  
     @JSFProperty
 317  
     public String getCurrencyCode()
 318  
     {
 319  0
         return _currencyCode != null ?
 320  
                _currencyCode :
 321  
                getDecimalFormatSymbols().getInternationalCurrencySymbol();
 322  
     }
 323  
 
 324  
     public void setCurrencyCode(String currencyCode)
 325  
     {
 326  0
         _currencyCode = currencyCode;
 327  0
     }
 328  
 
 329  
     /**
 330  
      * The currency symbol used to format a currency value.  Defaults
 331  
      * to the currency symbol for locale.
 332  
      * 
 333  
      */
 334  
     @JSFProperty
 335  
     public String getCurrencySymbol()
 336  
     {
 337  0
         return _currencySymbol != null ?
 338  
                _currencySymbol :
 339  
                getDecimalFormatSymbols().getCurrencySymbol();
 340  
     }
 341  
 
 342  
     public void setCurrencySymbol(String currencySymbol)
 343  
     {
 344  0
         _currencySymbol = currencySymbol;
 345  0
     }
 346  
 
 347  
     /**
 348  
      * Specifies whether output will contain grouping separators.  Default: true.
 349  
      * 
 350  
      */
 351  
     @JSFProperty
 352  
     public boolean isGroupingUsed()
 353  
     {
 354  0
         return _groupingUsed;
 355  
     }
 356  
 
 357  
     public void setGroupingUsed(boolean groupingUsed)
 358  
     {
 359  0
         _groupingUsed = groupingUsed;
 360  0
     }
 361  
 
 362  
     /**
 363  
      * Specifies whether only the integer part of the input will be parsed.  Default: false.
 364  
      * 
 365  
      */
 366  
     @JSFProperty
 367  
     public boolean isIntegerOnly()
 368  
     {
 369  0
         return _integerOnly;
 370  
     }
 371  
 
 372  
     public void setIntegerOnly(boolean integerOnly)
 373  
     {
 374  0
         _integerOnly = integerOnly;
 375  0
     }
 376  
 
 377  
     /**
 378  
      * The name of the locale to be used, instead of the default as
 379  
      * specified in the faces configuration file.
 380  
      * 
 381  
      */
 382  
     @JSFProperty
 383  
     public Locale getLocale()
 384  
     {
 385  0
         if (_locale != null) return _locale;
 386  0
         FacesContext context = FacesContext.getCurrentInstance();
 387  0
         return context.getViewRoot().getLocale();
 388  
     }
 389  
 
 390  
     public void setLocale(Locale locale)
 391  
     {
 392  0
         _locale = locale;
 393  0
     }
 394  
 
 395  
     /**
 396  
      * The maximum number of digits in the fractional portion of the number.
 397  
      * 
 398  
      */
 399  
     @JSFProperty
 400  
     public int getMaxFractionDigits()
 401  
     {
 402  0
         return _maxFractionDigits;
 403  
     }
 404  
 
 405  
     public void setMaxFractionDigits(int maxFractionDigits)
 406  
     {
 407  0
         _maxFractionDigitsSet = true;
 408  0
         _maxFractionDigits = maxFractionDigits;
 409  0
     }
 410  
 
 411  
     /**
 412  
      * The maximum number of digits in the integer portion of the number.
 413  
      * 
 414  
      */
 415  
     @JSFProperty
 416  
     public int getMaxIntegerDigits()
 417  
     {
 418  0
         return _maxIntegerDigits;
 419  
     }
 420  
 
 421  
     public void setMaxIntegerDigits(int maxIntegerDigits)
 422  
     {
 423  0
         _maxIntegerDigitsSet = true;
 424  0
         _maxIntegerDigits = maxIntegerDigits;
 425  0
     }
 426  
 
 427  
     /**
 428  
      * The minimum number of digits in the fractional portion of the number.
 429  
      * 
 430  
      */
 431  
     @JSFProperty
 432  
     public int getMinFractionDigits()
 433  
     {
 434  0
         return _minFractionDigits;
 435  
     }
 436  
 
 437  
     public void setMinFractionDigits(int minFractionDigits)
 438  
     {
 439  0
         _minFractionDigitsSet = true;
 440  0
         _minFractionDigits = minFractionDigits;
 441  0
     }
 442  
 
 443  
     /**
 444  
      * The minimum number of digits in the integer portion of the number.
 445  
      * 
 446  
      */
 447  
     @JSFProperty
 448  
     public int getMinIntegerDigits()
 449  
     {
 450  0
         return _minIntegerDigits;
 451  
     }
 452  
 
 453  
     public void setMinIntegerDigits(int minIntegerDigits)
 454  
     {
 455  0
         _minIntegerDigitsSet = true;
 456  0
         _minIntegerDigits = minIntegerDigits;
 457  0
     }
 458  
 
 459  
     /**
 460  
      * A custom Date formatting pattern, in the format used by java.text.SimpleDateFormat.
 461  
      * 
 462  
      */
 463  
     @JSFProperty
 464  
     public String getPattern()
 465  
     {
 466  0
         return _pattern;
 467  
     }
 468  
 
 469  
     public void setPattern(String pattern)
 470  
     {
 471  0
         _pattern = pattern;
 472  0
     }
 473  
 
 474  
     public boolean isTransient()
 475  
     {
 476  0
         return _transient;
 477  
     }
 478  
 
 479  
     public void setTransient(boolean aTransient)
 480  
     {
 481  0
         _transient = aTransient;
 482  0
     }
 483  
 
 484  
     /**
 485  
      * The type of formatting/parsing to be performed.  Values include:
 486  
      * number, currency, and percent.  Default: number.
 487  
      * 
 488  
      */
 489  
     @JSFProperty
 490  
     public String getType()
 491  
     {
 492  0
         return _type;
 493  
     }
 494  
 
 495  
     public void setType(String type)
 496  
     {
 497  
         //TODO: validate type
 498  0
         _type = type;
 499  0
     }
 500  
 
 501  
     private static boolean checkJavaVersion14()
 502  
     {
 503  0
         String version = System.getProperty("java.version");
 504  0
         if (version == null)
 505  
         {
 506  0
             return false;
 507  
         }
 508  0
         byte java14 = 0;
 509  0
         for (int idx = version.indexOf('.'), i = 0; idx > 0 || version != null; i++)
 510  
         {
 511  0
             if (idx > 0)
 512  
             {
 513  0
                 byte value = Byte.parseByte(version.substring(0, 1));
 514  0
                 version = version.substring(idx + 1, version.length());
 515  0
                 idx = version.indexOf('.');
 516  0
                 switch (i)
 517  
                 {
 518  
                     case 0:
 519  0
                         if (value == 1)
 520  
                         {
 521  0
                             java14 = 1;
 522  0
                             break;
 523  
                         }
 524  0
                         else if (value > 1)
 525  
                         {
 526  0
                             java14 = 2;
 527  
                         }
 528  
                     case 1:
 529  0
                         if (java14 > 0 && value >= 4)
 530  
                         {
 531  0
                             java14 = 2;
 532  
                         }
 533  
                         ;
 534  
                     default:
 535  0
                         idx = 0;
 536  0
                         version = null;
 537  
                         break;
 538  
                 }
 539  0
             }
 540  
             else
 541  
             {
 542  0
                 byte value = Byte.parseByte(version.substring(0, 1));
 543  0
                 if (java14 > 0 && value >= 4)
 544  
                 {
 545  0
                     java14 = 2;
 546  
                 }
 547  
                 break;
 548  
             }
 549  
         }
 550  0
         return java14 == 2;
 551  
     }
 552  
 
 553  
 
 554  
     private DecimalFormatSymbols getDecimalFormatSymbols()
 555  
     {
 556  0
         return new DecimalFormatSymbols(getLocale());
 557  
     }
 558  
 }