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