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 018 019package org.apache.commons.beanutils; 020 021 022import java.io.File; 023import java.lang.reflect.Array; 024import java.math.BigDecimal; 025import java.math.BigInteger; 026import java.net.URL; 027import java.sql.Timestamp; 028import java.util.Calendar; 029import java.util.Collection; 030 031import org.apache.commons.beanutils.converters.ArrayConverter; 032import org.apache.commons.beanutils.converters.BigDecimalConverter; 033import org.apache.commons.beanutils.converters.BigIntegerConverter; 034import org.apache.commons.beanutils.converters.BooleanConverter; 035import org.apache.commons.beanutils.converters.ByteConverter; 036import org.apache.commons.beanutils.converters.CalendarConverter; 037import org.apache.commons.beanutils.converters.CharacterConverter; 038import org.apache.commons.beanutils.converters.ClassConverter; 039import org.apache.commons.beanutils.converters.ConverterFacade; 040import org.apache.commons.beanutils.converters.DateConverter; 041import org.apache.commons.beanutils.converters.DoubleConverter; 042import org.apache.commons.beanutils.converters.FileConverter; 043import org.apache.commons.beanutils.converters.FloatConverter; 044import org.apache.commons.beanutils.converters.IntegerConverter; 045import org.apache.commons.beanutils.converters.LongConverter; 046import org.apache.commons.beanutils.converters.ShortConverter; 047import org.apache.commons.beanutils.converters.SqlDateConverter; 048import org.apache.commons.beanutils.converters.SqlTimeConverter; 049import org.apache.commons.beanutils.converters.SqlTimestampConverter; 050import org.apache.commons.beanutils.converters.StringConverter; 051import org.apache.commons.beanutils.converters.URLConverter; 052import org.apache.commons.logging.Log; 053import org.apache.commons.logging.LogFactory; 054 055 056/** 057 * <p>Utility methods for converting String scalar values to objects of the 058 * specified Class, String arrays to arrays of the specified Class. The 059 * actual {@link Converter} instance to be used can be registered for each 060 * possible destination Class. Unless you override them, standard 061 * {@link Converter} instances are provided for all of the following 062 * destination Classes:</p> 063 * <ul> 064 * <li>java.lang.BigDecimal (no default value)</li> 065 * <li>java.lang.BigInteger (no default value)</li> 066 * <li>boolean and java.lang.Boolean (default to false)</li> 067 * <li>byte and java.lang.Byte (default to zero)</li> 068 * <li>char and java.lang.Character (default to a space)</li> 069 * <li>java.lang.Class (no default value)</li> 070 * <li>double and java.lang.Double (default to zero)</li> 071 * <li>float and java.lang.Float (default to zero)</li> 072 * <li>int and java.lang.Integer (default to zero)</li> 073 * <li>long and java.lang.Long (default to zero)</li> 074 * <li>short and java.lang.Short (default to zero)</li> 075 * <li>java.lang.String (default to null)</li> 076 * <li>java.io.File (no default value)</li> 077 * <li>java.net.URL (no default value)</li> 078 * <li>java.sql.Date (no default value)</li> 079 * <li>java.sql.Time (no default value)</li> 080 * <li>java.sql.Timestamp (no default value)</li> 081 * </ul> 082 * 083 * <p>For backwards compatibility, the standard Converters for primitive 084 * types (and the corresponding wrapper classes) return a defined 085 * default value when a conversion error occurs. If you prefer to have a 086 * {@link ConversionException} thrown instead, replace the standard Converter 087 * instances with instances created with the zero-arguments constructor. For 088 * example, to cause the Converters for integers to throw an exception on 089 * conversion errors, you could do this:</p> 090 * <pre> 091 * // No-args constructor gets the version that throws exceptions 092 * Converter myConverter = 093 * new org.apache.commons.beanutils.converter.IntegerConverter(); 094 * ConvertUtils.register(myConverter, Integer.TYPE); // Native type 095 * ConvertUtils.register(myConverter, Integer.class); // Wrapper class 096 * </pre> 097 * 098 * <p> 099 * Converters generally treat null input as if it were invalid 100 * input, ie they return their default value if one was specified when the 101 * converter was constructed, and throw an exception otherwise. If you prefer 102 * nulls to be preserved for converters that are converting to objects (not 103 * primitives) then register a converter as above, passing a default value of 104 * null to the converter constructor (and of course registering that converter 105 * only for the .class target). 106 * </p> 107 * 108 * <p> 109 * When a converter is listed above as having no default value, then that 110 * converter will throw an exception when passed null or an invalid value 111 * as its input. In particular, by default the BigInteger and BigDecimal 112 * converters have no default (and are therefore somewhat inconsistent 113 * with the other numerical converters which all have zero as their default). 114 * </p> 115 * 116 * <p> 117 * Converters that generate <i>arrays</i> of each of the primitive types are 118 * also automatically configured (including String[]). When passed null 119 * or invalid input, these return an empty array (not null). See class 120 * AbstractArrayConverter for the supported input formats for these converters. 121 * </p> 122 * 123 * @version $Id$ 124 * @since 1.7 125 */ 126 127public class ConvertUtilsBean { 128 129 private static final Integer ZERO = new Integer(0); 130 private static final Character SPACE = new Character(' '); 131 132 // ------------------------------------------------------- Class Methods 133 /** 134 * Get singleton instance 135 * @return The singleton instance 136 */ 137 protected static ConvertUtilsBean getInstance() { 138 return BeanUtilsBean.getInstance().getConvertUtils(); 139 } 140 141 // ------------------------------------------------------- Variables 142 143 144 /** 145 * The set of {@link Converter}s that can be used to convert Strings 146 * into objects of a specified Class, keyed by the destination Class. 147 */ 148 private final WeakFastHashMap<Class<?>, Converter> converters = 149 new WeakFastHashMap<Class<?>, Converter>(); 150 151 /** 152 * The <code>Log</code> instance for this class. 153 */ 154 private final Log log = LogFactory.getLog(ConvertUtils.class); 155 156 // ------------------------------------------------------- Constructors 157 158 /** Construct a bean with standard converters registered */ 159 public ConvertUtilsBean() { 160 converters.setFast(false); 161 deregister(); 162 converters.setFast(true); 163 } 164 165 // --------------------------------------------------------- Public Methods 166 167 /** 168 * The default value for Boolean conversions. 169 * @deprecated Register replacement converters for Boolean.TYPE and 170 * Boolean.class instead 171 */ 172 @Deprecated 173 private Boolean defaultBoolean = Boolean.FALSE; 174 175 /** 176 * Gets the default value for Boolean conversions. 177 * @return The default Boolean value 178 * @deprecated Register replacement converters for Boolean.TYPE and 179 * Boolean.class instead 180 */ 181 @Deprecated 182 public boolean getDefaultBoolean() { 183 return (defaultBoolean.booleanValue()); 184 } 185 186 /** 187 * Sets the default value for Boolean conversions. 188 * @param newDefaultBoolean The default Boolean value 189 * @deprecated Register replacement converters for Boolean.TYPE and 190 * Boolean.class instead 191 */ 192 @Deprecated 193 public void setDefaultBoolean(final boolean newDefaultBoolean) { 194 defaultBoolean = (newDefaultBoolean ? Boolean.TRUE : Boolean.FALSE); 195 register(new BooleanConverter(defaultBoolean), Boolean.TYPE); 196 register(new BooleanConverter(defaultBoolean), Boolean.class); 197 } 198 199 200 /** 201 * The default value for Byte conversions. 202 * @deprecated Register replacement converters for Byte.TYPE and 203 * Byte.class instead 204 */ 205 @Deprecated 206 private Byte defaultByte = new Byte((byte) 0); 207 208 /** 209 * Gets the default value for Byte conversions. 210 * @return The default Byte value 211 * @deprecated Register replacement converters for Byte.TYPE and 212 * Byte.class instead 213 */ 214 @Deprecated 215 public byte getDefaultByte() { 216 return (defaultByte.byteValue()); 217 } 218 219 /** 220 * Sets the default value for Byte conversions. 221 * @param newDefaultByte The default Byte value 222 * @deprecated Register replacement converters for Byte.TYPE and 223 * Byte.class instead 224 */ 225 @Deprecated 226 public void setDefaultByte(final byte newDefaultByte) { 227 defaultByte = new Byte(newDefaultByte); 228 register(new ByteConverter(defaultByte), Byte.TYPE); 229 register(new ByteConverter(defaultByte), Byte.class); 230 } 231 232 233 /** 234 * The default value for Character conversions. 235 * @deprecated Register replacement converters for Character.TYPE and 236 * Character.class instead 237 */ 238 @Deprecated 239 private Character defaultCharacter = new Character(' '); 240 241 /** 242 * Gets the default value for Character conversions. 243 * @return The default Character value 244 * @deprecated Register replacement converters for Character.TYPE and 245 * Character.class instead 246 */ 247 @Deprecated 248 public char getDefaultCharacter() { 249 return (defaultCharacter.charValue()); 250 } 251 252 /** 253 * Sets the default value for Character conversions. 254 * @param newDefaultCharacter The default Character value 255 * @deprecated Register replacement converters for Character.TYPE and 256 * Character.class instead 257 */ 258 @Deprecated 259 public void setDefaultCharacter(final char newDefaultCharacter) { 260 defaultCharacter = new Character(newDefaultCharacter); 261 register(new CharacterConverter(defaultCharacter), 262 Character.TYPE); 263 register(new CharacterConverter(defaultCharacter), 264 Character.class); 265 } 266 267 268 /** 269 * The default value for Double conversions. 270 * @deprecated Register replacement converters for Double.TYPE and 271 * Double.class instead 272 */ 273 @Deprecated 274 private Double defaultDouble = new Double(0.0); 275 276 /** 277 * Gets the default value for Double conversions. 278 * @return The default Double value 279 * @deprecated Register replacement converters for Double.TYPE and 280 * Double.class instead 281 */ 282 @Deprecated 283 public double getDefaultDouble() { 284 return (defaultDouble.doubleValue()); 285 } 286 287 /** 288 * Sets the default value for Double conversions. 289 * @param newDefaultDouble The default Double value 290 * @deprecated Register replacement converters for Double.TYPE and 291 * Double.class instead 292 */ 293 @Deprecated 294 public void setDefaultDouble(final double newDefaultDouble) { 295 defaultDouble = new Double(newDefaultDouble); 296 register(new DoubleConverter(defaultDouble), Double.TYPE); 297 register(new DoubleConverter(defaultDouble), Double.class); 298 } 299 300 301 /** 302 * The default value for Float conversions. 303 * @deprecated Register replacement converters for Float.TYPE and 304 * Float.class instead 305 */ 306 @Deprecated 307 private Float defaultFloat = new Float((float) 0.0); 308 309 /** 310 * Gets the default value for Float conversions. 311 * @return The default Float value 312 * @deprecated Register replacement converters for Float.TYPE and 313 * Float.class instead 314 */ 315 @Deprecated 316 public float getDefaultFloat() { 317 return (defaultFloat.floatValue()); 318 } 319 320 /** 321 * Sets the default value for Float conversions. 322 * @param newDefaultFloat The default Float value 323 * @deprecated Register replacement converters for Float.TYPE and 324 * Float.class instead 325 */ 326 @Deprecated 327 public void setDefaultFloat(final float newDefaultFloat) { 328 defaultFloat = new Float(newDefaultFloat); 329 register(new FloatConverter(defaultFloat), Float.TYPE); 330 register(new FloatConverter(defaultFloat), Float.class); 331 } 332 333 334 /** 335 * The default value for Integer conversions. 336 * @deprecated Register replacement converters for Integer.TYPE and 337 * Integer.class instead 338 */ 339 @Deprecated 340 private Integer defaultInteger = new Integer(0); 341 342 /** 343 * Gets the default value for Integer conversions. 344 * @return The default Integer value 345 * @deprecated Register replacement converters for Integer.TYPE and 346 * Integer.class instead 347 */ 348 @Deprecated 349 public int getDefaultInteger() { 350 return (defaultInteger.intValue()); 351 } 352 353 /** 354 * Sets the default value for Integer conversions. 355 * @param newDefaultInteger The default Integer value 356 * @deprecated Register replacement converters for Integer.TYPE and 357 * Integer.class instead 358 */ 359 @Deprecated 360 public void setDefaultInteger(final int newDefaultInteger) { 361 defaultInteger = new Integer(newDefaultInteger); 362 register(new IntegerConverter(defaultInteger), Integer.TYPE); 363 register(new IntegerConverter(defaultInteger), Integer.class); 364 } 365 366 367 /** 368 * The default value for Long conversions. 369 * @deprecated Register replacement converters for Long.TYPE and 370 * Long.class instead 371 */ 372 @Deprecated 373 private Long defaultLong = new Long(0); 374 375 /** 376 * Gets the default value for Long conversions. 377 * @return The default Long value 378 * @deprecated Register replacement converters for Long.TYPE and 379 * Long.class instead 380 */ 381 @Deprecated 382 public long getDefaultLong() { 383 return (defaultLong.longValue()); 384 } 385 386 /** 387 * Sets the default value for Long conversions. 388 * @param newDefaultLong The default Long value 389 * @deprecated Register replacement converters for Long.TYPE and 390 * Long.class instead 391 */ 392 @Deprecated 393 public void setDefaultLong(final long newDefaultLong) { 394 defaultLong = new Long(newDefaultLong); 395 register(new LongConverter(defaultLong), Long.TYPE); 396 register(new LongConverter(defaultLong), Long.class); 397 } 398 399 400 /** 401 * The default value for Short conversions. 402 * @deprecated Register replacement converters for Short.TYPE and 403 * Short.class instead 404 */ 405 @Deprecated 406 private static Short defaultShort = new Short((short) 0); 407 408 /** 409 * Gets the default value for Short conversions. 410 * @return The default Short value 411 * @deprecated Register replacement converters for Short.TYPE and 412 * Short.class instead 413 */ 414 @Deprecated 415 public short getDefaultShort() { 416 return (defaultShort.shortValue()); 417 } 418 419 /** 420 * Sets the default value for Short conversions. 421 * @param newDefaultShort The default Short value 422 * @deprecated Register replacement converters for Short.TYPE and 423 * Short.class instead 424 */ 425 @Deprecated 426 public void setDefaultShort(final short newDefaultShort) { 427 defaultShort = new Short(newDefaultShort); 428 register(new ShortConverter(defaultShort), Short.TYPE); 429 register(new ShortConverter(defaultShort), Short.class); 430 } 431 432 433 434 /** 435 * Convert the specified value into a String. If the specified value 436 * is an array, the first element (converted to a String) will be 437 * returned. The registered {@link Converter} for the 438 * <code>java.lang.String</code> class will be used, which allows 439 * applications to customize Object->String conversions (the default 440 * implementation simply uses toString()). 441 * 442 * @param value Value to be converted (may be null) 443 * @return The converted String value or null if value is null 444 */ 445 public String convert(Object value) { 446 447 if (value == null) { 448 return null; 449 } else if (value.getClass().isArray()) { 450 if (Array.getLength(value) < 1) { 451 return (null); 452 } 453 value = Array.get(value, 0); 454 if (value == null) { 455 return null; 456 } else { 457 final Converter converter = lookup(String.class); 458 return (converter.convert(String.class, value)); 459 } 460 } else { 461 final Converter converter = lookup(String.class); 462 return (converter.convert(String.class, value)); 463 } 464 465 } 466 467 468 /** 469 * Convert the specified value to an object of the specified class (if 470 * possible). Otherwise, return a String representation of the value. 471 * 472 * @param value Value to be converted (may be null) 473 * @param clazz Java class to be converted to (must not be null) 474 * @return The converted value 475 * 476 * @throws ConversionException if thrown by an underlying Converter 477 */ 478 public Object convert(final String value, final Class<?> clazz) { 479 480 if (log.isDebugEnabled()) { 481 log.debug("Convert string '" + value + "' to class '" + 482 clazz.getName() + "'"); 483 } 484 Converter converter = lookup(clazz); 485 if (converter == null) { 486 converter = lookup(String.class); 487 } 488 if (log.isTraceEnabled()) { 489 log.trace(" Using converter " + converter); 490 } 491 return (converter.convert(clazz, value)); 492 493 } 494 495 496 /** 497 * Convert an array of specified values to an array of objects of the 498 * specified class (if possible). If the specified Java class is itself 499 * an array class, this class will be the type of the returned value. 500 * Otherwise, an array will be constructed whose component type is the 501 * specified class. 502 * 503 * @param values Array of values to be converted 504 * @param clazz Java array or element class to be converted to (must not be null) 505 * @return The converted value 506 * 507 * @throws ConversionException if thrown by an underlying Converter 508 */ 509 public Object convert(final String[] values, final Class<?> clazz) { 510 511 Class<?> type = clazz; 512 if (clazz.isArray()) { 513 type = clazz.getComponentType(); 514 } 515 if (log.isDebugEnabled()) { 516 log.debug("Convert String[" + values.length + "] to class '" + 517 type.getName() + "[]'"); 518 } 519 Converter converter = lookup(type); 520 if (converter == null) { 521 converter = lookup(String.class); 522 } 523 if (log.isTraceEnabled()) { 524 log.trace(" Using converter " + converter); 525 } 526 final Object array = Array.newInstance(type, values.length); 527 for (int i = 0; i < values.length; i++) { 528 Array.set(array, i, converter.convert(type, values[i])); 529 } 530 return (array); 531 532 } 533 534 535 /** 536 * Convert the value to an object of the specified class (if 537 * possible). If no converter for the desired target type is registered, 538 * the passed in object is returned unchanged. 539 * 540 * @param value Value to be converted (may be null) 541 * @param targetType Class of the value to be converted to (must not be null) 542 * @return The converted value 543 * 544 * @throws ConversionException if thrown by an underlying Converter 545 */ 546 public Object convert(final Object value, final Class<?> targetType) { 547 548 final Class<?> sourceType = value == null ? null : value.getClass(); 549 550 if (log.isDebugEnabled()) { 551 if (value == null) { 552 log.debug("Convert null value to type '" + 553 targetType.getName() + "'"); 554 } else { 555 log.debug("Convert type '" + sourceType.getName() + "' value '" + value + 556 "' to type '" + targetType.getName() + "'"); 557 } 558 } 559 560 Object converted = value; 561 Converter converter = lookup(sourceType, targetType); 562 if (converter != null) { 563 if (log.isTraceEnabled()) { 564 log.trace(" Using converter " + converter); 565 } 566 converted = converter.convert(targetType, value); 567 } 568 if (String.class.equals(targetType) && converted != null && 569 !(converted instanceof String)) { 570 571 // NOTE: For backwards compatibility, if the Converter 572 // doesn't handle conversion-->String then 573 // use the registered String Converter 574 converter = lookup(String.class); 575 if (converter != null) { 576 if (log.isTraceEnabled()) { 577 log.trace(" Using converter " + converter); 578 } 579 converted = converter.convert(String.class, converted); 580 } 581 582 // If the object still isn't a String, use toString() method 583 if (converted != null && !(converted instanceof String)) { 584 converted = converted.toString(); 585 } 586 587 } 588 return converted; 589 590 } 591 592 /** 593 * Remove all registered {@link Converter}s, and re-establish the 594 * standard Converters. 595 */ 596 public void deregister() { 597 598 converters.clear(); 599 600 registerPrimitives(false); 601 registerStandard(false, false); 602 registerOther(true); 603 registerArrays(false, 0); 604 register(BigDecimal.class, new BigDecimalConverter()); 605 register(BigInteger.class, new BigIntegerConverter()); 606 } 607 608 /** 609 * Register the provided converters with the specified defaults. 610 * 611 * @param throwException <code>true</code> if the converters should 612 * throw an exception when a conversion error occurs, otherwise 613 * <code>false</code> if a default value should be used. 614 * @param defaultNull <code>true</code>if the <i>standard</i> converters 615 * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)}) 616 * should use a default value of <code>null</code>, otherwise <code>false</code>. 617 * N.B. This values is ignored if <code>throwException</code> is <code>true</code> 618 * @param defaultArraySize The size of the default array value for array converters 619 * (N.B. This values is ignored if <code>throwException</code> is <code>true</code>). 620 * Specifying a value less than zero causes a <code>null</code> value to be used for 621 * the default. 622 */ 623 public void register(final boolean throwException, final boolean defaultNull, final int defaultArraySize) { 624 registerPrimitives(throwException); 625 registerStandard(throwException, defaultNull); 626 registerOther(throwException); 627 registerArrays(throwException, defaultArraySize); 628 } 629 630 /** 631 * Register the converters for primitive types. 632 * </p> 633 * This method registers the following converters: 634 * <ul> 635 * <li><code>Boolean.TYPE</code> - {@link BooleanConverter}</li> 636 * <li><code>Byte.TYPE</code> - {@link ByteConverter}</li> 637 * <li><code>Character.TYPE</code> - {@link CharacterConverter}</li> 638 * <li><code>Double.TYPE</code> - {@link DoubleConverter}</li> 639 * <li><code>Float.TYPE</code> - {@link FloatConverter}</li> 640 * <li><code>Integer.TYPE</code> - {@link IntegerConverter}</li> 641 * <li><code>Long.TYPE</code> - {@link LongConverter}</li> 642 * <li><code>Short.TYPE</code> - {@link ShortConverter}</li> 643 * </ul> 644 * @param throwException <code>true</code> if the converters should 645 * throw an exception when a conversion error occurs, otherwise <code> 646 * <code>false</code> if a default value should be used. 647 */ 648 private void registerPrimitives(final boolean throwException) { 649 register(Boolean.TYPE, throwException ? new BooleanConverter() : new BooleanConverter(Boolean.FALSE)); 650 register(Byte.TYPE, throwException ? new ByteConverter() : new ByteConverter(ZERO)); 651 register(Character.TYPE, throwException ? new CharacterConverter() : new CharacterConverter(SPACE)); 652 register(Double.TYPE, throwException ? new DoubleConverter() : new DoubleConverter(ZERO)); 653 register(Float.TYPE, throwException ? new FloatConverter() : new FloatConverter(ZERO)); 654 register(Integer.TYPE, throwException ? new IntegerConverter() : new IntegerConverter(ZERO)); 655 register(Long.TYPE, throwException ? new LongConverter() : new LongConverter(ZERO)); 656 register(Short.TYPE, throwException ? new ShortConverter() : new ShortConverter(ZERO)); 657 } 658 659 /** 660 * Register the converters for standard types. 661 * </p> 662 * This method registers the following converters: 663 * <ul> 664 * <li><code>BigDecimal.class</code> - {@link BigDecimalConverter}</li> 665 * <li><code>BigInteger.class</code> - {@link BigIntegerConverter}</li> 666 * <li><code>Boolean.class</code> - {@link BooleanConverter}</li> 667 * <li><code>Byte.class</code> - {@link ByteConverter}</li> 668 * <li><code>Character.class</code> - {@link CharacterConverter}</li> 669 * <li><code>Double.class</code> - {@link DoubleConverter}</li> 670 * <li><code>Float.class</code> - {@link FloatConverter}</li> 671 * <li><code>Integer.class</code> - {@link IntegerConverter}</li> 672 * <li><code>Long.class</code> - {@link LongConverter}</li> 673 * <li><code>Short.class</code> - {@link ShortConverter}</li> 674 * <li><code>String.class</code> - {@link StringConverter}</li> 675 * </ul> 676 * @param throwException <code>true</code> if the converters should 677 * throw an exception when a conversion error occurs, otherwise <code> 678 * <code>false</code> if a default value should be used. 679 * @param defaultNull <code>true</code>if the <i>standard</i> converters 680 * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)}) 681 * should use a default value of <code>null</code>, otherwise <code>false</code>. 682 * N.B. This values is ignored if <code>throwException</code> is <code>true</code> 683 */ 684 private void registerStandard(final boolean throwException, final boolean defaultNull) { 685 686 final Number defaultNumber = defaultNull ? null : ZERO; 687 final BigDecimal bigDecDeflt = defaultNull ? null : new BigDecimal("0.0"); 688 final BigInteger bigIntDeflt = defaultNull ? null : new BigInteger("0"); 689 final Boolean booleanDefault = defaultNull ? null : Boolean.FALSE; 690 final Character charDefault = defaultNull ? null : SPACE; 691 final String stringDefault = defaultNull ? null : ""; 692 693 register(BigDecimal.class, throwException ? new BigDecimalConverter() : new BigDecimalConverter(bigDecDeflt)); 694 register(BigInteger.class, throwException ? new BigIntegerConverter() : new BigIntegerConverter(bigIntDeflt)); 695 register(Boolean.class, throwException ? new BooleanConverter() : new BooleanConverter(booleanDefault)); 696 register(Byte.class, throwException ? new ByteConverter() : new ByteConverter(defaultNumber)); 697 register(Character.class, throwException ? new CharacterConverter() : new CharacterConverter(charDefault)); 698 register(Double.class, throwException ? new DoubleConverter() : new DoubleConverter(defaultNumber)); 699 register(Float.class, throwException ? new FloatConverter() : new FloatConverter(defaultNumber)); 700 register(Integer.class, throwException ? new IntegerConverter() : new IntegerConverter(defaultNumber)); 701 register(Long.class, throwException ? new LongConverter() : new LongConverter(defaultNumber)); 702 register(Short.class, throwException ? new ShortConverter() : new ShortConverter(defaultNumber)); 703 register(String.class, throwException ? new StringConverter() : new StringConverter(stringDefault)); 704 705 } 706 707 /** 708 * Register the converters for other types. 709 * </p> 710 * This method registers the following converters: 711 * <ul> 712 * <li><code>Class.class</code> - {@link ClassConverter}</li> 713 * <li><code>java.util.Date.class</code> - {@link DateConverter}</li> 714 * <li><code>java.util.Calendar.class</code> - {@link CalendarConverter}</li> 715 * <li><code>File.class</code> - {@link FileConverter}</li> 716 * <li><code>java.sql.Date.class</code> - {@link SqlDateConverter}</li> 717 * <li><code>java.sql.Time.class</code> - {@link SqlTimeConverter}</li> 718 * <li><code>java.sql.Timestamp.class</code> - {@link SqlTimestampConverter}</li> 719 * <li><code>URL.class</code> - {@link URLConverter}</li> 720 * </ul> 721 * @param throwException <code>true</code> if the converters should 722 * throw an exception when a conversion error occurs, otherwise <code> 723 * <code>false</code> if a default value should be used. 724 */ 725 private void registerOther(final boolean throwException) { 726 register(Class.class, throwException ? new ClassConverter() : new ClassConverter(null)); 727 register(java.util.Date.class, throwException ? new DateConverter() : new DateConverter(null)); 728 register(Calendar.class, throwException ? new CalendarConverter() : new CalendarConverter(null)); 729 register(File.class, throwException ? new FileConverter() : new FileConverter(null)); 730 register(java.sql.Date.class, throwException ? new SqlDateConverter() : new SqlDateConverter(null)); 731 register(java.sql.Time.class, throwException ? new SqlTimeConverter() : new SqlTimeConverter(null)); 732 register(Timestamp.class, throwException ? new SqlTimestampConverter() : new SqlTimestampConverter(null)); 733 register(URL.class, throwException ? new URLConverter() : new URLConverter(null)); 734 } 735 736 /** 737 * Register array converters. 738 * 739 * @param throwException <code>true</code> if the converters should 740 * throw an exception when a conversion error occurs, otherwise <code> 741 * <code>false</code> if a default value should be used. 742 * @param defaultArraySize The size of the default array value for array converters 743 * (N.B. This values is ignored if <code>throwException</code> is <code>true</code>). 744 * Specifying a value less than zero causes a <code>null<code> value to be used for 745 * the default. 746 */ 747 private void registerArrays(final boolean throwException, final int defaultArraySize) { 748 749 // Primitives 750 registerArrayConverter(Boolean.TYPE, new BooleanConverter(), throwException, defaultArraySize); 751 registerArrayConverter(Byte.TYPE, new ByteConverter(), throwException, defaultArraySize); 752 registerArrayConverter(Character.TYPE, new CharacterConverter(), throwException, defaultArraySize); 753 registerArrayConverter(Double.TYPE, new DoubleConverter(), throwException, defaultArraySize); 754 registerArrayConverter(Float.TYPE, new FloatConverter(), throwException, defaultArraySize); 755 registerArrayConverter(Integer.TYPE, new IntegerConverter(), throwException, defaultArraySize); 756 registerArrayConverter(Long.TYPE, new LongConverter(), throwException, defaultArraySize); 757 registerArrayConverter(Short.TYPE, new ShortConverter(), throwException, defaultArraySize); 758 759 // Standard 760 registerArrayConverter(BigDecimal.class, new BigDecimalConverter(), throwException, defaultArraySize); 761 registerArrayConverter(BigInteger.class, new BigIntegerConverter(), throwException, defaultArraySize); 762 registerArrayConverter(Boolean.class, new BooleanConverter(), throwException, defaultArraySize); 763 registerArrayConverter(Byte.class, new ByteConverter(), throwException, defaultArraySize); 764 registerArrayConverter(Character.class, new CharacterConverter(), throwException, defaultArraySize); 765 registerArrayConverter(Double.class, new DoubleConverter(), throwException, defaultArraySize); 766 registerArrayConverter(Float.class, new FloatConverter(), throwException, defaultArraySize); 767 registerArrayConverter(Integer.class, new IntegerConverter(), throwException, defaultArraySize); 768 registerArrayConverter(Long.class, new LongConverter(), throwException, defaultArraySize); 769 registerArrayConverter(Short.class, new ShortConverter(), throwException, defaultArraySize); 770 registerArrayConverter(String.class, new StringConverter(), throwException, defaultArraySize); 771 772 // Other 773 registerArrayConverter(Class.class, new ClassConverter(), throwException, defaultArraySize); 774 registerArrayConverter(java.util.Date.class, new DateConverter(), throwException, defaultArraySize); 775 registerArrayConverter(Calendar.class, new DateConverter(), throwException, defaultArraySize); 776 registerArrayConverter(File.class, new FileConverter(), throwException, defaultArraySize); 777 registerArrayConverter(java.sql.Date.class, new SqlDateConverter(), throwException, defaultArraySize); 778 registerArrayConverter(java.sql.Time.class, new SqlTimeConverter(), throwException, defaultArraySize); 779 registerArrayConverter(Timestamp.class, new SqlTimestampConverter(), throwException, defaultArraySize); 780 registerArrayConverter(URL.class, new URLConverter(), throwException, defaultArraySize); 781 782 } 783 784 /** 785 * Register a new ArrayConverter with the specified element delegate converter 786 * that returns a default array of the specified size in the event of conversion errors. 787 * 788 * @param componentType The component type of the array 789 * @param componentConverter The converter to delegate to for the array elements 790 * @param throwException Whether a conversion exception should be thrown or a default 791 * value used in the event of a conversion error 792 * @param defaultArraySize The size of the default array 793 */ 794 private void registerArrayConverter(final Class<?> componentType, final Converter componentConverter, 795 final boolean throwException, final int defaultArraySize) { 796 final Class<?> arrayType = Array.newInstance(componentType, 0).getClass(); 797 Converter arrayConverter = null; 798 if (throwException) { 799 arrayConverter = new ArrayConverter(arrayType, componentConverter); 800 } else { 801 arrayConverter = new ArrayConverter(arrayType, componentConverter, defaultArraySize); 802 } 803 register(arrayType, arrayConverter); 804 } 805 806 /** strictly for convenience since it has same parameter order as Map.put */ 807 private void register(final Class<?> clazz, final Converter converter) { 808 register(new ConverterFacade(converter), clazz); 809 } 810 811 /** 812 * Remove any registered {@link Converter} for the specified destination 813 * <code>Class</code>. 814 * 815 * @param clazz Class for which to remove a registered Converter 816 */ 817 public void deregister(final Class<?> clazz) { 818 819 converters.remove(clazz); 820 821 } 822 823 824 /** 825 * Look up and return any registered {@link Converter} for the specified 826 * destination class; if there is no registered Converter, return 827 * <code>null</code>. 828 * 829 * @param clazz Class for which to return a registered Converter 830 * @return The registered {@link Converter} or <code>null</code> if not found 831 */ 832 public Converter lookup(final Class<?> clazz) { 833 834 return (converters.get(clazz)); 835 836 } 837 838 /** 839 * Look up and return any registered {@link Converter} for the specified 840 * source and destination class; if there is no registered Converter, 841 * return <code>null</code>. 842 * 843 * @param sourceType Class of the value being converted 844 * @param targetType Class of the value to be converted to 845 * @return The registered {@link Converter} or <code>null</code> if not found 846 */ 847 public Converter lookup(final Class<?> sourceType, final Class<?> targetType) { 848 849 if (targetType == null) { 850 throw new IllegalArgumentException("Target type is missing"); 851 } 852 if (sourceType == null) { 853 return lookup(targetType); 854 } 855 856 Converter converter = null; 857 // Convert --> String 858 if (targetType == String.class) { 859 converter = lookup(sourceType); 860 if (converter == null && (sourceType.isArray() || 861 Collection.class.isAssignableFrom(sourceType))) { 862 converter = lookup(String[].class); 863 } 864 if (converter == null) { 865 converter = lookup(String.class); 866 } 867 return converter; 868 } 869 870 // Convert --> String array 871 if (targetType == String[].class) { 872 if (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType)) { 873 converter = lookup(sourceType); 874 } 875 if (converter == null) { 876 converter = lookup(String[].class); 877 } 878 return converter; 879 } 880 881 return lookup(targetType); 882 883 } 884 885 /** 886 * Register a custom {@link Converter} for the specified destination 887 * <code>Class</code>, replacing any previously registered Converter. 888 * 889 * @param converter Converter to be registered 890 * @param clazz Destination class for conversions performed by this 891 * Converter 892 */ 893 public void register(final Converter converter, final Class<?> clazz) { 894 895 converters.put(clazz, converter); 896 897 } 898}