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 * http://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 package org.apache.commons.validator;
018
019 import java.io.Serializable;
020 import java.util.Date;
021 import java.util.Locale;
022 import java.text.DateFormat;
023 import java.text.SimpleDateFormat;
024 import java.text.NumberFormat;
025 import java.text.ParseException;
026 import java.text.ParsePosition;
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029
030 /**
031 * This class contains basic methods for performing validations that return the
032 * correctly typed class based on the validation performed.
033 *
034 * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $
035 */
036 public class GenericTypeValidator implements Serializable {
037
038 private static final long serialVersionUID = 5487162314134261703L;
039
040 /**
041 * Checks if the value can safely be converted to a byte primitive.
042 *
043 *@param value The value validation is being performed on.
044 *@return the converted Byte value.
045 */
046 public static Byte formatByte(String value) {
047 if (value == null) {
048 return null;
049 }
050
051 try {
052 return new Byte(value);
053 } catch (NumberFormatException e) {
054 return null;
055 }
056
057 }
058
059 /**
060 * Checks if the value can safely be converted to a byte primitive.
061 *
062 *@param value The value validation is being performed on.
063 *@param locale The locale to use to parse the number (system default if
064 * null)
065 *@return the converted Byte value.
066 */
067 public static Byte formatByte(String value, Locale locale) {
068 Byte result = null;
069
070 if (value != null) {
071 NumberFormat formatter = null;
072 if (locale != null) {
073 formatter = NumberFormat.getNumberInstance(locale);
074 } else {
075 formatter = NumberFormat.getNumberInstance(Locale.getDefault());
076 }
077 formatter.setParseIntegerOnly(true);
078 ParsePosition pos = new ParsePosition(0);
079 Number num = formatter.parse(value, pos);
080
081 // If there was no error and we used the whole string
082 if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
083 if (num.doubleValue() >= Byte.MIN_VALUE &&
084 num.doubleValue() <= Byte.MAX_VALUE) {
085 result = new Byte(num.byteValue());
086 }
087 }
088 }
089
090 return result;
091 }
092
093 /**
094 * Checks if the value can safely be converted to a short primitive.
095 *
096 *@param value The value validation is being performed on.
097 *@return the converted Short value.
098 */
099 public static Short formatShort(String value) {
100 if (value == null) {
101 return null;
102 }
103
104 try {
105 return new Short(value);
106 } catch (NumberFormatException e) {
107 return null;
108 }
109
110 }
111
112 /**
113 * Checks if the value can safely be converted to a short primitive.
114 *
115 *@param value The value validation is being performed on.
116 *@param locale The locale to use to parse the number (system default if
117 * null)vv
118 *@return the converted Short value.
119 */
120 public static Short formatShort(String value, Locale locale) {
121 Short result = null;
122
123 if (value != null) {
124 NumberFormat formatter = null;
125 if (locale != null) {
126 formatter = NumberFormat.getNumberInstance(locale);
127 } else {
128 formatter = NumberFormat.getNumberInstance(Locale.getDefault());
129 }
130 formatter.setParseIntegerOnly(true);
131 ParsePosition pos = new ParsePosition(0);
132 Number num = formatter.parse(value, pos);
133
134 // If there was no error and we used the whole string
135 if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
136 if (num.doubleValue() >= Short.MIN_VALUE &&
137 num.doubleValue() <= Short.MAX_VALUE) {
138 result = new Short(num.shortValue());
139 }
140 }
141 }
142
143 return result;
144 }
145
146 /**
147 * Checks if the value can safely be converted to a int primitive.
148 *
149 *@param value The value validation is being performed on.
150 *@return the converted Integer value.
151 */
152 public static Integer formatInt(String value) {
153 if (value == null) {
154 return null;
155 }
156
157 try {
158 return new Integer(value);
159 } catch (NumberFormatException e) {
160 return null;
161 }
162
163 }
164
165 /**
166 * Checks if the value can safely be converted to an int primitive.
167 *
168 *@param value The value validation is being performed on.
169 *@param locale The locale to use to parse the number (system default if
170 * null)
171 *@return the converted Integer value.
172 */
173 public static Integer formatInt(String value, Locale locale) {
174 Integer result = null;
175
176 if (value != null) {
177 NumberFormat formatter = null;
178 if (locale != null) {
179 formatter = NumberFormat.getNumberInstance(locale);
180 } else {
181 formatter = NumberFormat.getNumberInstance(Locale.getDefault());
182 }
183 formatter.setParseIntegerOnly(true);
184 ParsePosition pos = new ParsePosition(0);
185 Number num = formatter.parse(value, pos);
186
187 // If there was no error and we used the whole string
188 if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
189 if (num.doubleValue() >= Integer.MIN_VALUE &&
190 num.doubleValue() <= Integer.MAX_VALUE) {
191 result = new Integer(num.intValue());
192 }
193 }
194 }
195
196 return result;
197 }
198
199 /**
200 * Checks if the value can safely be converted to a long primitive.
201 *
202 *@param value The value validation is being performed on.
203 *@return the converted Long value.
204 */
205 public static Long formatLong(String value) {
206 if (value == null) {
207 return null;
208 }
209
210 try {
211 return new Long(value);
212 } catch (NumberFormatException e) {
213 return null;
214 }
215
216 }
217
218 /**
219 * Checks if the value can safely be converted to a long primitive.
220 *
221 *@param value The value validation is being performed on.
222 *@param locale The locale to use to parse the number (system default if
223 * null)
224 *@return the converted Long value.
225 */
226 public static Long formatLong(String value, Locale locale) {
227 Long result = null;
228
229 if (value != null) {
230 NumberFormat formatter = null;
231 if (locale != null) {
232 formatter = NumberFormat.getNumberInstance(locale);
233 } else {
234 formatter = NumberFormat.getNumberInstance(Locale.getDefault());
235 }
236 formatter.setParseIntegerOnly(true);
237 ParsePosition pos = new ParsePosition(0);
238 Number num = formatter.parse(value, pos);
239
240 // If there was no error and we used the whole string
241 if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
242 if (num.doubleValue() >= Long.MIN_VALUE &&
243 num.doubleValue() <= Long.MAX_VALUE) {
244 result = new Long(num.longValue());
245 }
246 }
247 }
248
249 return result;
250 }
251
252 /**
253 * Checks if the value can safely be converted to a float primitive.
254 *
255 *@param value The value validation is being performed on.
256 *@return the converted Float value.
257 */
258 public static Float formatFloat(String value) {
259 if (value == null) {
260 return null;
261 }
262
263 try {
264 return new Float(value);
265 } catch (NumberFormatException e) {
266 return null;
267 }
268
269 }
270
271 /**
272 * Checks if the value can safely be converted to a float primitive.
273 *
274 *@param value The value validation is being performed on.
275 *@param locale The locale to use to parse the number (system default if
276 * null)
277 *@return the converted Float value.
278 */
279 public static Float formatFloat(String value, Locale locale) {
280 Float result = null;
281
282 if (value != null) {
283 NumberFormat formatter = null;
284 if (locale != null) {
285 formatter = NumberFormat.getInstance(locale);
286 } else {
287 formatter = NumberFormat.getInstance(Locale.getDefault());
288 }
289 ParsePosition pos = new ParsePosition(0);
290 Number num = formatter.parse(value, pos);
291
292 // If there was no error and we used the whole string
293 if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
294 if (num.doubleValue() >= (Float.MAX_VALUE * -1) &&
295 num.doubleValue() <= Float.MAX_VALUE) {
296 result = new Float(num.floatValue());
297 }
298 }
299 }
300
301 return result;
302 }
303
304 /**
305 * Checks if the value can safely be converted to a double primitive.
306 *
307 *@param value The value validation is being performed on.
308 *@return the converted Double value.
309 */
310 public static Double formatDouble(String value) {
311 if (value == null) {
312 return null;
313 }
314
315 try {
316 return new Double(value);
317 } catch (NumberFormatException e) {
318 return null;
319 }
320
321 }
322
323 /**
324 * Checks if the value can safely be converted to a double primitive.
325 *
326 *@param value The value validation is being performed on.
327 *@param locale The locale to use to parse the number (system default if
328 * null)
329 *@return the converted Double value.
330 */
331 public static Double formatDouble(String value, Locale locale) {
332 Double result = null;
333
334 if (value != null) {
335 NumberFormat formatter = null;
336 if (locale != null) {
337 formatter = NumberFormat.getInstance(locale);
338 } else {
339 formatter = NumberFormat.getInstance(Locale.getDefault());
340 }
341 ParsePosition pos = new ParsePosition(0);
342 Number num = formatter.parse(value, pos);
343
344 // If there was no error and we used the whole string
345 if (pos.getErrorIndex() == -1 && pos.getIndex() == value.length()) {
346 if (num.doubleValue() >= (Double.MAX_VALUE * -1) &&
347 num.doubleValue() <= Double.MAX_VALUE) {
348 result = new Double(num.doubleValue());
349 }
350 }
351 }
352
353 return result;
354 }
355
356 /**
357 * <p>
358 *
359 * Checks if the field is a valid date. The <code>Locale</code> is used
360 * with <code>java.text.DateFormat</code>. The setLenient method is set to
361 * <code>false</code> for all.</p>
362 *
363 *@param value The value validation is being performed on.
364 *@param locale The Locale to use to parse the date (system default if
365 * null)
366 *@return the converted Date value.
367 */
368 public static Date formatDate(String value, Locale locale) {
369 Date date = null;
370
371 if (value == null) {
372 return null;
373 }
374
375 try {
376 // Get the formatters to check against
377 DateFormat formatterShort = null;
378 DateFormat formatterDefault = null;
379 if (locale != null) {
380 formatterShort =
381 DateFormat.getDateInstance(DateFormat.SHORT, locale);
382 formatterDefault =
383 DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
384 } else {
385 formatterShort =
386 DateFormat.getDateInstance(
387 DateFormat.SHORT,
388 Locale.getDefault());
389 formatterDefault =
390 DateFormat.getDateInstance(
391 DateFormat.DEFAULT,
392 Locale.getDefault());
393 }
394
395 // Turn off lenient parsing
396 formatterShort.setLenient(false);
397 formatterDefault.setLenient(false);
398
399 // Firstly, try with the short form
400 try {
401 date = formatterShort.parse(value);
402 } catch (ParseException e) {
403 // Fall back on the default one
404 date = formatterDefault.parse(value);
405 }
406 } catch (ParseException e) {
407 // Bad date, so log and return null
408 Log log = LogFactory.getLog(GenericTypeValidator.class);
409 if (log.isDebugEnabled()) {
410 log.debug("Date parse failed value=[" + value + "], " +
411 "locale=[" + locale + "] " + e);
412 }
413 }
414
415 return date;
416 }
417
418 /**
419 * <p>
420 * Checks if the field is a valid date. The pattern is used with <code>java.text.SimpleDateFormat</code>
421 * . If strict is true, then the length will be checked so '2/12/1999' will
422 * not pass validation with the format 'MM/dd/yyyy' because the month isn't
423 * two digits. The setLenient method is set to <code>false</code> for all.
424 * </p>
425 *
426 *@param value The value validation is being performed on.
427 *@param datePattern The pattern passed to <code>SimpleDateFormat</code>.
428 *@param strict Whether or not to have an exact match of the
429 * datePattern.
430 *@return the converted Date value.
431 */
432 public static Date formatDate(String value, String datePattern, boolean strict) {
433 Date date = null;
434
435 if (value == null
436 || datePattern == null
437 || datePattern.length() == 0) {
438 return null;
439 }
440
441 try {
442 SimpleDateFormat formatter = new SimpleDateFormat(datePattern);
443 formatter.setLenient(false);
444
445 date = formatter.parse(value);
446
447 if (strict) {
448 if (datePattern.length() != value.length()) {
449 date = null;
450 }
451 }
452 } catch (ParseException e) {
453 // Bad date so return null
454 Log log = LogFactory.getLog(GenericTypeValidator.class);
455 if (log.isDebugEnabled()) {
456 log.debug("Date parse failed value=[" + value + "], " +
457 "pattern=[" + datePattern + "], " +
458 "strict=[" + strict + "] " + e);
459 }
460 }
461
462 return date;
463 }
464
465 /**
466 * <p>
467 * Checks if the field is a valid credit card number.</p> <p>
468 *
469 * Reference Sean M. Burke's <a href="http://www.ling.nwu.edu/~sburke/pub/luhn_lib.pl">
470 * script</a> .</p>
471 *
472 *@param value The value validation is being performed on.
473 *@return the converted Credit Card number.
474 */
475 public static Long formatCreditCard(String value) {
476 return GenericValidator.isCreditCard(value) ? new Long(value) : null;
477 }
478
479 }
480