1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.commons.validator.routines;
22
23 import java.text.DecimalFormat;
24 import java.text.Format;
25 import java.math.BigDecimal;
26
27 /***
28 * <p><b>Percentage Validation</b> and Conversion routines (<code>java.math.BigDecimal</code>).</p>
29 *
30 * <p>This is one implementation of a percent validator that has the following features:</p>
31 * <ul>
32 * <li>It is <i>lenient</i> about the the presence of the <i>percent symbol</i></li>
33 * <li>It converts the percent to a <code>java.math.BigDecimal</code></li>
34 * </ul>
35 *
36 * <p>However any of the <i>number</i> validators can be used for <i>percent</i> validation.
37 * For example, if you wanted a <i>percent</i> validator that converts to a
38 * <code>java.lang.Float</code> then you can simply instantiate an
39 * <code>FloatValidator</code> with the appropriate <i>format type</i>:</p>
40 *
41 * <p><code>... = new FloatValidator(false, FloatValidator.PERCENT_FORMAT);</code></p>
42 *
43 * <p>Pick the appropriate validator, depending on the type (i.e Float, Double or BigDecimal)
44 * you want the percent converted to. Please note, it makes no sense to use
45 * one of the validators that doesn't handle fractions (i.e. byte, short, integer, long
46 * and BigInteger) since percentages are converted to fractions (i.e <code>50%</code> is
47 * converted to <code>0.5</code>).</p>
48 *
49 * @version $Revision: 386637 $ $Date: 2006-03-17 13:22:26 +0000 (Fri, 17 Mar 2006) $
50 * @since Validator 1.3.0
51 */
52 public class PercentValidator extends BigDecimalValidator {
53
54 private static final PercentValidator VALIDATOR = new PercentValidator();
55
56 /*** DecimalFormat's percent (thousand multiplier) symbol */
57 private static final char PERCENT_SYMBOL = '%';
58
59 private static final BigDecimal POINT_ZERO_ONE = new BigDecimal("0.01");
60
61 /***
62 * Return a singleton instance of this validator.
63 * @return A singleton instance of the PercentValidator.
64 */
65 public static BigDecimalValidator getInstance() {
66 return VALIDATOR;
67 }
68
69 /***
70 * Construct a <i>strict</i> instance.
71 */
72 public PercentValidator() {
73 this(true);
74 }
75
76 /***
77 * Construct an instance with the specified strict setting.
78 *
79 * @param strict <code>true</code> if strict
80 * <code>Format</code> parsing should be used.
81 */
82 public PercentValidator(boolean strict) {
83 super(strict, PERCENT_FORMAT, true);
84 }
85
86 /***
87 * <p>Parse the value with the specified <code>Format</code>.</p>
88 *
89 * <p>This implementation is lenient whether the currency symbol
90 * is present or not. The default <code>NumberFormat</code>
91 * behaviour is for the parsing to "fail" if the currency
92 * symbol is missing. This method re-parses with a format
93 * without the currency symbol if it fails initially.</p>
94 *
95 * @param value The value to be parsed.
96 * @param formatter The Format to parse the value with.
97 * @return The parsed value if valid or <code>null</code> if invalid.
98 */
99 protected Object parse(String value, Format formatter) {
100
101
102 BigDecimal parsedValue = (BigDecimal)super.parse(value, formatter);
103 if (parsedValue != null || !(formatter instanceof DecimalFormat)) {
104 return parsedValue;
105 }
106
107
108 DecimalFormat decimalFormat = (DecimalFormat)formatter;
109 String pattern = decimalFormat.toPattern();
110 if (pattern.indexOf(PERCENT_SYMBOL) >= 0) {
111 StringBuffer buffer = new StringBuffer(pattern.length());
112 for (int i = 0; i < pattern.length(); i++) {
113 if (pattern.charAt(i) != PERCENT_SYMBOL) {
114 buffer.append(pattern.charAt(i));
115 }
116 }
117 decimalFormat.applyPattern(buffer.toString());
118 parsedValue = (BigDecimal)super.parse(value, decimalFormat);
119
120
121 if (parsedValue != null) {
122 parsedValue = parsedValue.multiply(POINT_ZERO_ONE);
123 }
124
125 }
126 return parsedValue;
127 }
128 }