001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.validator.routines; 019 020import java.math.BigDecimal; 021import java.text.DecimalFormat; 022import java.text.Format; 023import java.text.NumberFormat; 024import java.util.Locale; 025 026/** 027 * <strong>BigDecimal Validation</strong> and Conversion routines ({@code java.math.BigDecimal}). 028 * <p> 029 * This validator provides a number of methods for validating/converting a {@link String} value to a {@code BigDecimal} using {@link NumberFormat} to parse 030 * either: 031 * </p> 032 * <ul> 033 * <li>using the default format for the default {@link Locale}</li> 034 * <li>using a specified pattern with the default {@link Locale}</li> 035 * <li>using the default format for a specified {@link Locale}</li> 036 * <li>using a specified pattern with a specified {@link Locale}</li> 037 * </ul> 038 * <p> 039 * Use one of the {@code isValid()} methods to just validate or one of the {@code validate()} methods to validate and receive a <em>converted</em> 040 * {@code BigDecimal} value. 041 * </p> 042 * <p> 043 * Fraction/decimal values are automatically trimmed to the appropriate length. 044 * </p> 045 * <p> 046 * Once a value has been successfully converted the following methods can be used to perform minimum, maximum and range checks: 047 * </p> 048 * <ul> 049 * <li>{@code minValue()} checks whether the value is greater than or equal to a specified minimum.</li> 050 * <li>{@code maxValue()} checks whether the value is less than or equal to a specified maximum.</li> 051 * <li>{@code isInRange()} checks whether the value is within a specified range of values.</li> 052 * </ul> 053 * <p> 054 * So that the same mechanism used for parsing an <em>input</em> value for validation can be used to format <em>output</em>, corresponding {@code format()} 055 * methods are also provided. That is you can format either: 056 * </p> 057 * <ul> 058 * <li>using the default format for the default {@link Locale}</li> 059 * <li>using a specified pattern with the default {@link Locale}</li> 060 * <li>using the default format for a specified {@link Locale}</li> 061 * <li>using a specified pattern with a specified {@link Locale}</li> 062 * </ul> 063 * 064 * @since 1.3.0 065 */ 066public class BigDecimalValidator extends AbstractNumberValidator { 067 068 private static final long serialVersionUID = -670320911490506772L; 069 private static final BigDecimalValidator VALIDATOR = new BigDecimalValidator(); 070 071 /** 072 * Compares the given {@code BigDecimal} with the given double value. 073 * 074 * @param bigDecimal The {@code BigDecimal} to compare. 075 * @param value The double value to compare with. 076 * @return A negative integer, zero, or a positive integer as this {@code BigDecimal} is less than, equal to, or greater than the specified double value. 077 */ 078 private static int compareTo(final BigDecimal bigDecimal, final double value) { 079 return bigDecimal.compareTo(BigDecimal.valueOf(value)); 080 } 081 082 /** 083 * Gets the singleton instance of this validator. 084 * 085 * @return A singleton instance of the BigDecimalValidator. 086 */ 087 public static BigDecimalValidator getInstance() { 088 return VALIDATOR; 089 } 090 091 /** 092 * Constructs a <em>strict</em> instance. 093 */ 094 public BigDecimalValidator() { 095 this(true); 096 } 097 098 /** 099 * Construct an instance with the specified strict setting. 100 * 101 * @param strict {@code true} if strict {@code Format} parsing should be used. 102 */ 103 public BigDecimalValidator(final boolean strict) { 104 this(strict, STANDARD_FORMAT, true); 105 } 106 107 /** 108 * Constructs an instance with the specified strict setting and format type. 109 * <p> 110 * The {@code formatType} specified what type of {@code NumberFormat} is created - valid types are: 111 * </p> 112 * <ul> 113 * <li>AbstractNumberValidator.STANDARD_FORMAT -to create <em>standard</em> number formats (the default).</li> 114 * <li>AbstractNumberValidator.CURRENCY_FORMAT -to create <em>currency</em> number formats.</li> 115 * <li>AbstractNumberValidator.PERCENT_FORMAT -to create <em>percent</em> number formats (the default).</li> 116 * </ul> 117 * 118 * @param strict {@code true} if strict {@code Format} parsing should be used. 119 * @param formatType The {@code NumberFormat} type to create for validation, default is STANDARD_FORMAT. 120 * @param allowFractions {@code true} if fractions are allowed or {@code false} if integers only. 121 */ 122 protected BigDecimalValidator(final boolean strict, final int formatType, final boolean allowFractions) { 123 super(strict, formatType, allowFractions); 124 } 125 126 /** 127 * Returns a {@code Format} that parses to a {@code BigDecimal} so the exact value of the input is preserved. 128 * 129 * <p> 130 * The superclass leaves {@link DecimalFormat} in its default mode, where {@code parse} yields a {@code Double} for a 131 * fractional value and so rounds an input carrying more significant digits than a {@code double} can hold. Enabling 132 * {@link DecimalFormat#setParseBigDecimal(boolean)} keeps the value as a {@code BigDecimal} through parsing. 133 * </p> 134 * 135 * @param pattern The pattern used to validate the value against or {@code null} to use the default for the {@link Locale}. 136 * @param locale The locale to use for the format, system default if null. 137 * @return The {@code Format} to use. 138 */ 139 @Override 140 protected Format getFormat(final String pattern, final Locale locale) { 141 return setParseBigDecimal(super.getFormat(pattern, locale)); 142 } 143 144 /** 145 * Tests if the value is within a specified range. 146 * 147 * @param value The {@code Number} value to check. 148 * @param min The minimum value of the range. 149 * @param max The maximum value of the range. 150 * @return {@code true} if the value is within the specified range. 151 */ 152 public boolean isInRange(final BigDecimal value, final double min, final double max) { 153 return minValue(value, min) && maxValue(value, max); 154 } 155 156 /** 157 * Tests if the value is less than or equal to a maximum. 158 * 159 * @param value The value validation is being performed on. 160 * @param max The maximum value. 161 * @return {@code true} if the value is less than or equal to the maximum. 162 */ 163 public boolean maxValue(final BigDecimal value, final double max) { 164 return Double.isFinite(max) ? compareTo(value, max) <= 0 : value.doubleValue() <= max; 165 } 166 167 /** 168 * Tests if the value is less than or equal to a maximum, comparing the exact values. 169 * 170 * <p> 171 * This overrides the {@link Number} overload inherited from the superclass, which narrows the value to a {@code double} before comparing and so loses 172 * precision for a {@code BigDecimal} that differs from the bound only beyond double precision. A non-finite {@link Double} or {@link Float} operand keeps 173 * the {@code doubleValue()} comparison so the documented infinity behavior is unchanged. 174 * </p> 175 * 176 * @param value The value validation is being performed on. 177 * @param max The maximum value. 178 * @return {@code true} if the value is less than or equal to the maximum. 179 */ 180 @Override 181 public boolean maxValue(final Number value, final Number max) { 182 return isFinite(value) && isFinite(max) ? compareTo(value, max) <= 0 : value.doubleValue() <= max.doubleValue(); 183 } 184 185 /** 186 * Tests if the value is greater than or equal to a minimum. 187 * 188 * @param value The value validation is being performed on. 189 * @param min The minimum value. 190 * @return {@code true} if the value is greater than or equal to the minimum. 191 */ 192 public boolean minValue(final BigDecimal value, final double min) { 193 return Double.isFinite(min) ? compareTo(value, min) >= 0 : value.doubleValue() >= min; 194 } 195 196 /** 197 * Tests if the value is greater than or equal to a minimum, comparing the exact values. 198 * 199 * <p> 200 * This overrides the {@link Number} overload inherited from the superclass, which narrows the value to a {@code double} before comparing and so loses 201 * precision for a {@code BigDecimal} that differs from the bound only beyond double precision. A non-finite {@link Double} or {@link Float} operand keeps 202 * the {@code doubleValue()} comparison so the documented infinity behavior is unchanged. 203 * </p> 204 * 205 * @param value The value validation is being performed on. 206 * @param min The minimum value. 207 * @return {@code true} if the value is greater than or equal to the minimum. 208 */ 209 @Override 210 public boolean minValue(final Number value, final Number min) { 211 return isFinite(value) && isFinite(min) ? compareTo(value, min) >= 0 : value.doubleValue() >= min.doubleValue(); 212 } 213 214 /** 215 * Converts the parsed value to a {@code BigDecimal}. 216 * 217 * @param value The parsed {@code Number} object created. 218 * @param formatter The Format used to parse the value with. 219 * @return The parsed {@code Number} converted to a {@code BigDecimal}. 220 */ 221 @Override 222 protected Object processParsedValue(final Object value, final Format formatter) { 223 BigDecimal decimal = toBigDecimal(value); 224 final int scale = determineScale((NumberFormat) formatter); 225 if (scale >= 0) { 226 decimal = decimal.setScale(scale, BigDecimal.ROUND_DOWN); 227 } 228 return decimal; 229 } 230 231 /** 232 * Validates and converts a {@code BigDecimal} using the default {@link Locale}. 233 * 234 * @param value The value validation is being performed on. 235 * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid. 236 */ 237 public BigDecimal validate(final String value) { 238 return (BigDecimal) parse(value, (String) null, (Locale) null); 239 } 240 241 /** 242 * Validates and converts a {@code BigDecimal} using the specified {@link Locale}. 243 * 244 * @param value The value validation is being performed on. 245 * @param locale The locale to use for the number format, system default if null. 246 * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid. 247 */ 248 public BigDecimal validate(final String value, final Locale locale) { 249 return (BigDecimal) parse(value, (String) null, locale); 250 } 251 252 /** 253 * Validates and converts a {@code BigDecimal} using the specified <em>pattern</em>. 254 * 255 * @param value The value validation is being performed on. 256 * @param pattern The pattern used to validate the value against, or the default for the {@link Locale} if {@code null}. 257 * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid. 258 */ 259 public BigDecimal validate(final String value, final String pattern) { 260 return (BigDecimal) parse(value, pattern, (Locale) null); 261 } 262 263 /** 264 * Validates and converts a {@code BigDecimal} using the specified pattern and/ or {@link Locale}. 265 * 266 * @param value The value validation is being performed on. 267 * @param pattern The pattern used to validate the value against, or the default for the {@link Locale} if {@code null}. 268 * @param locale The locale to use for the date format, system default if null. 269 * @return The parsed {@code BigDecimal} if valid or {@code null} if invalid. 270 */ 271 public BigDecimal validate(final String value, final String pattern, final Locale locale) { 272 return (BigDecimal) parse(value, pattern, locale); 273 } 274}