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