View Javadoc

1   /*
2    * $Id: CurrencyValidator.java 386637 2006-03-17 13:22:26Z niallp $
3    * $Revision: 386637 $
4    * $Date: 2006-03-17 13:22:26 +0000 (Fri, 17 Mar 2006) $
5    *
6    * ====================================================================
7    * Copyright 2006 The Apache Software Foundation
8    *
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   *
13   *     http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   */
21  package org.apache.commons.validator.routines;
22  
23  import java.text.DecimalFormat;
24  import java.text.Format;
25  
26  /***
27   * <p><b>Currency Validation</b> and Conversion routines (<code>java.math.BigDecimal</code>).</p>
28   * 
29   * <p>This is one implementation of a currency validator that has the following features:</p>
30   *    <ul>
31   *       <li>It is <i>lenient</i> about the the presence of the <i>currency symbol</i></li>
32   *       <li>It converts the currency to a <code>java.math.BigDecimal</code></li>
33   *    </ul>
34   * 
35   * <p>However any of the <i>number</i> validators can be used for <i>currency</i> validation.
36   *    For example, if you wanted a <i>currency</i> validator that converts to a
37   *    <code>java.lang.Integer</code> then you can simply instantiate an
38   *    <code>IntegerValidator</code> with the appropriate <i>format type</i>:</p>
39   *    
40   *    <p><code>... = new IntegerValidator(false, IntegerValidator.CURRENCY_FORMAT);</code></p>
41   *
42   * <p>Pick the appropriate validator, depending on the type (e.g Float, Double, Integer, Long etc)
43   *    you want the currency converted to. One thing to note - only the CurrencyValidator
44   *    implements <i>lenient</i> behaviour regarding the currency symbol.</p>
45   * 
46   * @version $Revision: 386637 $ $Date: 2006-03-17 13:22:26 +0000 (Fri, 17 Mar 2006) $
47   * @since Validator 1.3.0
48   */
49  public class CurrencyValidator extends BigDecimalValidator {
50  
51      private static final CurrencyValidator VALIDATOR = new CurrencyValidator();
52  
53      /*** DecimalFormat's currency symbol */
54      private static final char CURRENCY_SYMBOL = '\u00A4';
55  
56      /***
57       * Return a singleton instance of this validator.
58       * @return A singleton instance of the CurrencyValidator.
59       */
60      public static BigDecimalValidator getInstance() {
61          return VALIDATOR;
62      }
63  
64      /***
65       * Construct a <i>strict</i> instance.
66       */
67      public CurrencyValidator() {
68          this(true, true);
69      }
70  
71      /***
72       * Construct an instance with the specified strict setting.
73       * 
74       * @param strict <code>true</code> if strict 
75       *        <code>Format</code> parsing should be used.
76       * @param allowFractions <code>true</code> if fractions are
77       *        allowed or <code>false</code> if integers only.
78       */
79      public CurrencyValidator(boolean strict, boolean allowFractions) {
80          super(strict, CURRENCY_FORMAT, allowFractions);
81      }
82  
83      /***
84       * <p>Parse the value with the specified <code>Format</code>.</p>
85       * 
86       * <p>This implementation is lenient whether the currency symbol
87       *    is present or not. The default <code>NumberFormat</code>
88       *    behaviour is for the parsing to "fail" if the currency
89       *    symbol is missing. This method re-parses with a format
90       *    without the currency symbol if it fails initially.</p>
91       * 
92       * @param value The value to be parsed.
93       * @param formatter The Format to parse the value with.
94       * @return The parsed value if valid or <code>null</code> if invalid.
95       */
96      protected Object parse(String value, Format formatter) {
97  
98          // Initial parse of the value
99          Object parsedValue = super.parse(value, formatter);
100         if (parsedValue != null || !(formatter instanceof DecimalFormat)) {
101             return parsedValue;
102         }
103 
104         // Re-parse using a pattern without the currency symbol
105         DecimalFormat decimalFormat = (DecimalFormat)formatter;
106         String pattern = decimalFormat.toPattern();
107         if (pattern.indexOf(CURRENCY_SYMBOL) >= 0) {
108             StringBuffer buffer = new StringBuffer(pattern.length());
109             for (int i = 0; i < pattern.length(); i++) {
110                 if (pattern.charAt(i) != CURRENCY_SYMBOL) {
111                     buffer.append(pattern.charAt(i));
112                 }
113             }
114             decimalFormat.applyPattern(buffer.toString());
115             parsedValue = super.parse(value, decimalFormat);
116         }
117         return parsedValue;
118     }
119 }