    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}