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 */ 017package org.apache.commons.validator; 018 019import java.io.Serializable; 020import java.util.Date; 021import java.util.Locale; 022import java.text.DateFormat; 023import java.text.SimpleDateFormat; 024import java.text.NumberFormat; 025import java.text.ParseException; 026import java.text.ParsePosition; 027import org.apache.commons.logging.Log; 028import 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 12:45:51 -0500 (Thu, 05 Jan 2012) $ 035 */ 036public 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