View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.validator.routines;
18  
19  import java.math.BigDecimal;
20  import java.text.Format;
21  import java.text.NumberFormat;
22  import java.util.Locale;
23  
24  /**
25   * <p><strong>BigDecimal Validation</strong> and Conversion routines ({@code java.math.BigDecimal}).</p>
26   *
27   * <p>This validator provides a number of methods for
28   *    validating/converting a {@link String} value to
29   *    a {@code BigDecimal} using {@link NumberFormat}
30   *    to parse either:</p>
31   *    <ul>
32   *       <li>using the default format for the default {@link Locale}</li>
33   *       <li>using a specified pattern with the default {@link Locale}</li>
34   *       <li>using the default format for a specified {@link Locale}</li>
35   *       <li>using a specified pattern with a specified {@link Locale}</li>
36   *    </ul>
37   *
38   * <p>Use one of the {@code isValid()} methods to just validate or
39   *    one of the {@code validate()} methods to validate and receive a
40   *    <em>converted</em> {@code BigDecimal} value.</p>
41   *
42   * <p>Fraction/decimal values are automatically trimmed to the appropriate length.</p>
43   *
44   * <p>Once a value has been successfully converted the following
45   *    methods can be used to perform minimum, maximum and range checks:</p>
46   *    <ul>
47   *       <li>{@code minValue()} checks whether the value is greater
48   *           than or equal to a specified minimum.</li>
49   *       <li>{@code maxValue()} checks whether the value is less
50   *           than or equal to a specified maximum.</li>
51   *       <li>{@code isInRange()} checks whether the value is within
52   *           a specified range of values.</li>
53   *    </ul>
54   *
55   * <p>So that the same mechanism used for parsing an <em>input</em> value
56   *    for validation can be used to format <em>output</em>, corresponding
57   *    {@code format()} methods are also provided. That is you can
58   *    format either:</p>
59   *    <ul>
60   *       <li>using the default format for the default {@link Locale}</li>
61   *       <li>using a specified pattern with the default {@link Locale}</li>
62   *       <li>using the default format for a specified {@link Locale}</li>
63   *       <li>using a specified pattern with a specified {@link Locale}</li>
64   *    </ul>
65   *
66   * @since 1.3.0
67   */
68  public class BigDecimalValidator extends AbstractNumberValidator {
69  
70      private static final long serialVersionUID = -670320911490506772L;
71  
72      private static final BigDecimalValidator VALIDATOR = new BigDecimalValidator();
73  
74      /**
75       * Gets the singleton instance of this validator.
76       *
77       * @return A singleton instance of the BigDecimalValidator.
78       */
79      public static BigDecimalValidator getInstance() {
80          return VALIDATOR;
81      }
82  
83      /**
84       * Constructs a <em>strict</em> instance.
85       */
86      public BigDecimalValidator() {
87          this(true);
88      }
89  
90      /**
91       * <p>Construct an instance with the specified strict setting.</p>
92       *
93       * @param strict {@code true} if strict
94       *        {@code Format} parsing should be used.
95       */
96      public BigDecimalValidator(final boolean strict) {
97          this(strict, STANDARD_FORMAT, true);
98      }
99  
100     /**
101      * <p>Construct an instance with the specified strict setting
102      *    and format type.</p>
103      *
104      * <p>The {@code formatType} specified what type of
105      *    {@code NumberFormat} is created - valid types
106      *    are:</p>
107      *    <ul>
108      *       <li>AbstractNumberValidator.STANDARD_FORMAT -to create
109      *           <em>standard</em> number formats (the default).</li>
110      *       <li>AbstractNumberValidator.CURRENCY_FORMAT -to create
111      *           <em>currency</em> number formats.</li>
112      *       <li>AbstractNumberValidator.PERCENT_FORMAT -to create
113      *           <em>percent</em> number formats (the default).</li>
114      *    </ul>
115      *
116      * @param strict {@code true} if strict
117      *        {@code Format} parsing should be used.
118      * @param formatType The {@code NumberFormat} type to
119      *        create for validation, default is STANDARD_FORMAT.
120      * @param allowFractions {@code true} if fractions are
121      *        allowed or {@code false} if integers only.
122      */
123     protected BigDecimalValidator(final boolean strict, final int formatType,
124             final boolean allowFractions) {
125         super(strict, formatType, allowFractions);
126     }
127 
128     /**
129      * Check if the value is within a specified range.
130      *
131      * @param value The {@code Number} value to check.
132      * @param min The minimum value of the range.
133      * @param max The maximum value of the range.
134      * @return {@code true} if the value is within the
135      *         specified range.
136      */
137     public boolean isInRange(final BigDecimal value, final double min, final double max) {
138         return value.doubleValue() >= min && value.doubleValue() <= max;
139     }
140 
141     /**
142      * Check if the value is less than or equal to a maximum.
143      *
144      * @param value The value validation is being performed on.
145      * @param max The maximum value.
146      * @return {@code true} if the value is less than
147      *         or equal to the maximum.
148      */
149     public boolean maxValue(final BigDecimal value, final double max) {
150         return value.doubleValue() <= max;
151     }
152 
153     /**
154      * Check if the value is greater than or equal to a minimum.
155      *
156      * @param value The value validation is being performed on.
157      * @param min The minimum value.
158      * @return {@code true} if the value is greater than
159      *         or equal to the minimum.
160      */
161     public boolean minValue(final BigDecimal value, final double min) {
162         return value.doubleValue() >= min;
163     }
164 
165     /**
166      * Convert the parsed value to a {@code BigDecimal}.
167      *
168      * @param value The parsed {@code Number} object created.
169      * @param formatter The Format used to parse the value with.
170      * @return The parsed {@code Number} converted to a
171      *         {@code BigDecimal}.
172      */
173     @Override
174     protected Object processParsedValue(final Object value, final Format formatter) {
175         BigDecimal decimal;
176         if (value instanceof Long) {
177             decimal = BigDecimal.valueOf(((Long) value).longValue());
178         } else {
179             decimal = new BigDecimal(value.toString());
180         }
181 
182         final int scale = determineScale((NumberFormat) formatter);
183         if (scale >= 0) {
184             decimal = decimal.setScale(scale, BigDecimal.ROUND_DOWN);
185         }
186 
187         return decimal;
188     }
189 
190     /**
191      * <p>Validate/convert a {@code BigDecimal} using the default
192      *    {@link Locale}.
193      *
194      * @param value The value validation is being performed on.
195      * @return The parsed {@code BigDecimal} if valid or {@code null}
196      *  if invalid.
197      */
198     public BigDecimal validate(final String value) {
199         return (BigDecimal) parse(value, (String) null, (Locale) null);
200     }
201 
202     /**
203      * <p>Validate/convert a {@code BigDecimal} using the
204      *    specified {@link Locale}.
205      *
206      * @param value The value validation is being performed on.
207      * @param locale The locale to use for the number format, system default if null.
208      * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid.
209      */
210     public BigDecimal validate(final String value, final Locale locale) {
211         return (BigDecimal) parse(value, (String) null, locale);
212     }
213 
214     /**
215      * <p>Validate/convert a {@code BigDecimal} using the
216      *    specified <em>pattern</em>.
217      *
218      * @param value The value validation is being performed on.
219      * @param pattern The pattern used to validate the value against, or the
220      *        default for the {@link Locale} if {@code null}.
221      * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid.
222      */
223     public BigDecimal validate(final String value, final String pattern) {
224         return (BigDecimal) parse(value, pattern, (Locale) null);
225     }
226 
227     /**
228      * <p>Validate/convert a {@code BigDecimal} using the
229      *    specified pattern and/ or {@link Locale}.
230      *
231      * @param value The value validation is being performed on.
232      * @param pattern The pattern used to validate the value against, or the
233      *        default for the {@link Locale} if {@code null}.
234      * @param locale The locale to use for the date format, system default if null.
235      * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid.
236      */
237     public BigDecimal validate(final String value, final String pattern, final Locale locale) {
238         return (BigDecimal) parse(value, pattern, locale);
239     }
240 }