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