    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.beanutils2;
    019
    020import java.awt.Color;
    021import java.awt.Dimension;
    022import java.awt.Point;
    023import java.io.File;
    024import java.lang.reflect.Array;
    025import java.math.BigDecimal;
    026import java.math.BigInteger;
    027import java.net.InetAddress;
    028import java.net.URI;
    029import java.net.URL;
    030import java.nio.file.Path;
    031import java.sql.Timestamp;
    032import java.time.Duration;
    033import java.time.LocalDate;
    034import java.time.LocalDateTime;
    035import java.time.LocalTime;
    036import java.time.MonthDay;
    037import java.time.OffsetDateTime;
    038import java.time.OffsetTime;
    039import java.time.Period;
    040import java.time.Year;
    041import java.time.YearMonth;
    042import java.time.ZoneId;
    043import java.time.ZoneOffset;
    044import java.time.ZonedDateTime;
    045import java.util.Calendar;
    046import java.util.Collection;
    047import java.util.Locale;
    048import java.util.Map;
    049import java.util.Objects;
    050import java.util.UUID;
    051import java.util.regex.Pattern;
    052
    053import org.apache.commons.beanutils2.converters.ArrayConverter;
    054import org.apache.commons.beanutils2.converters.BigDecimalConverter;
    055import org.apache.commons.beanutils2.converters.BigIntegerConverter;
    056import org.apache.commons.beanutils2.converters.BooleanConverter;
    057import org.apache.commons.beanutils2.converters.ByteConverter;
    058import org.apache.commons.beanutils2.converters.CalendarConverter;
    059import org.apache.commons.beanutils2.converters.CharacterConverter;
    060import org.apache.commons.beanutils2.converters.ClassConverter;
    061import org.apache.commons.beanutils2.converters.ColorConverter;
    062import org.apache.commons.beanutils2.converters.ConverterFacade;
    063import org.apache.commons.beanutils2.converters.DateConverter;
    064import org.apache.commons.beanutils2.converters.DimensionConverter;
    065import org.apache.commons.beanutils2.converters.DoubleConverter;
    066import org.apache.commons.beanutils2.converters.DurationConverter;
    067import org.apache.commons.beanutils2.converters.EnumConverter;
    068import org.apache.commons.beanutils2.converters.FileConverter;
    069import org.apache.commons.beanutils2.converters.FloatConverter;
    070import org.apache.commons.beanutils2.converters.InetAddressConverter;
    071import org.apache.commons.beanutils2.converters.IntegerConverter;
    072import org.apache.commons.beanutils2.converters.LocalDateConverter;
    073import org.apache.commons.beanutils2.converters.LocalDateTimeConverter;
    074import org.apache.commons.beanutils2.converters.LocalTimeConverter;
    075import org.apache.commons.beanutils2.converters.LocaleConverter;
    076import org.apache.commons.beanutils2.converters.LongConverter;
    077import org.apache.commons.beanutils2.converters.MonthDayConverter;
    078import org.apache.commons.beanutils2.converters.OffsetDateTimeConverter;
    079import org.apache.commons.beanutils2.converters.OffsetTimeConverter;
    080import org.apache.commons.beanutils2.converters.PathConverter;
    081import org.apache.commons.beanutils2.converters.PatternConverter;
    082import org.apache.commons.beanutils2.converters.PeriodConverter;
    083import org.apache.commons.beanutils2.converters.PointConverter;
    084import org.apache.commons.beanutils2.converters.ShortConverter;
    085import org.apache.commons.beanutils2.converters.StringConverter;
    086import org.apache.commons.beanutils2.converters.URIConverter;
    087import org.apache.commons.beanutils2.converters.URLConverter;
    088import org.apache.commons.beanutils2.converters.UUIDConverter;
    089import org.apache.commons.beanutils2.converters.YearConverter;
    090import org.apache.commons.beanutils2.converters.YearMonthConverter;
    091import org.apache.commons.beanutils2.converters.ZoneIdConverter;
    092import org.apache.commons.beanutils2.converters.ZoneOffsetConverter;
    093import org.apache.commons.beanutils2.converters.ZonedDateTimeConverter;
    094import org.apache.commons.beanutils2.sql.converters.SqlDateConverter;
    095import org.apache.commons.beanutils2.sql.converters.SqlTimeConverter;
    096import org.apache.commons.beanutils2.sql.converters.SqlTimestampConverter;
    097import org.apache.commons.logging.Log;
    098import org.apache.commons.logging.LogFactory;
    099
    100/**
    101 * TODO DOCS
    102 * <p>
    103 * 2.0
    104 * </p>
    105 *
    106 * {@link ConvertUtilsBean} implementation that delegates {@code convert()} methods to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
    107 *
    108 * <p>
    109 * To configure this implementation for the current context ClassLoader invoke {@code BeanUtilsBean.setInstance(new BeanUtilsBean2());}
    110 * </p>
    111 *
    112 * <p>
    113 * Pre-2.0
    114 * </p>
    115 *
    116 * <p>
    117 * Utility methods for converting String scalar values to objects of the specified Class, String arrays to arrays of the specified Class. The actual
    118 * {@link Converter} instance to be used can be registered for each possible destination Class. Unless you override them, standard {@link Converter} instances
    119 * are provided for all of the following destination Classes:
    120 * </p>
    121 * <ul>
    122 * <li>java.lang.BigDecimal (no default value)</li>
    123 * <li>java.lang.BigInteger (no default value)</li>
    124 * <li>boolean and java.lang.Boolean (default to false)</li>
    125 * <li>byte and java.lang.Byte (default to zero)</li>
    126 * <li>char and java.lang.Character (default to a space)</li>
    127 * <li>java.lang.Class (no default value)</li>
    128 * <li>java.awt.Color (no default value)</li>
    129 * <li>java.awt.Dimension (no default value)</li>
    130 * <li>double and java.lang.Double (default to zero)</li>
    131 * <li>float and java.lang.Float (default to zero)</li>
    132 * <li>int and java.lang.Integer (default to zero)</li>
    133 * <li>long and java.lang.Long (default to zero)</li>
    134 * <li>short and java.lang.Short (default to zero)</li>
    135 * <li>java.lang.String (default to null)</li>
    136 * <li>java.lang.Enum (default to null)</li>
    137 * <li>java.io.File (no default value)</li>
    138 * <li>java.net.InetAddress (no default value)</li>
    139 * <li>java.util.Locale (no default value)</li>
    140 * <li>java.nio.file.Path (no default value)</li>
    141 * <li>java.net.URL (no default value)</li>
    142 * <li>java.net.URI (no default value)</li>
    143 * <li>java.util.UUID (no default value)</li>
    144 * <li>java.sql.Date (no default value)</li>
    145 * <li>java.sql.Time (no default value)</li>
    146 * <li>java.sql.Timestamp (no default value)</li>
    147 * <li>java.time.LocalDate (no default value)</li>
    148 * <li>java.time.LocalDateTime (no default value)</li>
    149 * <li>java.time.LocalTime (no default value)</li>
    150 * <li>java.time.OffsetDateTime (no default value)</li>
    151 * <li>java.time.OffsetTime (no default value)</li>
    152 * <li>java.time.ZonedDateTime (no default value)</li>
    153 * <li>java.time.Duration (no default value)</li>
    154 * <li>java.time.MonthDay (no default value)</li>
    155 * <li>java.util.regex.Pattern (no default value)</li>
    156 * <li>java.time.Period (no default value)</li>
    157 * <li>java.awt.Point (no default value)</li>
    158 * <li>java.time.Year (no default value)</li>
    159 * <li>java.time.YearMonth (no default value)</li>
    160 * <li>java.time.ZoneId (no default value)</li>
    161 * <li>java.time.ZoneOffset (no default value)</li>
    162 * </ul>
    163 *
    164 * <p>
    165 * For backwards compatibility, the standard Converters for primitive types (and the corresponding wrapper classes) return a defined default value when a
    166 * conversion error occurs. If you prefer to have a {@link ConversionException} thrown instead, replace the standard Converter instances with instances created
    167 * with the zero-arguments constructor. For example, to cause the Converters for integers to throw an exception on conversion errors, you could do this:
    168 * </p>
    169 *
    170 * <pre>
    171 * // No-args constructor gets the version that throws exceptions
    172 * Converter myConverter = new org.apache.commons.beanutils2.converter.IntegerConverter();
    173 * ConvertUtils.register(myConverter, Integer.TYPE); // Native type
    174 * ConvertUtils.register(myConverter, Integer.class); // Wrapper class
    175 * </pre>
    176 *
    177 * <p>
    178 * Converters generally treat null input as if it were invalid input, that is, they return their default value if one was specified when the converter was
    179 * constructed, and throw an exception otherwise. If you prefer nulls to be preserved for converters that are converting to objects (not primitives) then
    180 * register a converter as above, passing a default value of null to the converter constructor (and of course registering that converter only for the .class
    181 * target).
    182 * </p>
    183 *
    184 * <p>
    185 * When a converter is listed above as having no default value, then that converter will throw an exception when passed null or an invalid value as its input.
    186 * In particular, by default the BigInteger and BigDecimal converters have no default (and are therefore somewhat inconsistent with the other numerical
    187 * converters which all have zero as their default).
    188 * </p>
    189 *
    190 * <p>
    191 * Converters that generate <em>arrays</em> of each of the primitive types are also automatically configured (including String[]). When passed null or invalid
    192 * input, these return an empty array (not null). See class AbstractArrayConverter for the supported input formats for these converters.
    193 * </p>
    194 *
    195 * @since 1.7
    196 */
    197public class ConvertUtilsBean {
    198
    199    private static final Integer ZERO = Integer.valueOf(0);
    200    private static final Character SPACE = Character.valueOf(' ');
    201
    202    /**
    203     * The {@code Log} instance for this class.
    204     */
    205    private static final Log LOG = LogFactory.getLog(ConvertUtilsBean.class);
    206
    207    /**
    208     * Gets singleton instance
    209     *
    210     * @return The singleton instance
    211     */
    212    protected static ConvertUtilsBean getInstance() {
    213        return BeanUtilsBean.getInstance().getConvertUtils();
    214    }
    215
    216    /**
    217     * The set of {@link Converter}s that can be used to convert Strings into objects of a specified Class, keyed by the destination Class.
    218     */
    219    private final Map<Class<?>, Converter<?>> converters = BeanUtils.createCache();
    220
    221    /** Constructs a bean with standard converters registered */
    222    public ConvertUtilsBean() {
    223        deregister();
    224    }
    225
    226    /**
    227     * Delegates to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
    228     *
    229     * @param value Value to be converted (may be null)
    230     * @return The converted String value or null if value is null
    231     * @see ConvertUtilsBean#convert(String[], Class)
    232     */
    233    public String convert(final Object value) {
    234        return (String) convert(value, String.class);
    235    }
    236
    237    /**
    238     * Converts the value to an object of the specified class (if possible). If no converter for the desired target type is registered, the passed in object is
    239     * returned unchanged.
    240     *
    241     * @param <T>        The Class type.
    242     * @param value      Value to be converted (may be null)
    243     * @param targetType Class of the value to be converted to (must not be null)
    244     * @return The converted value
    245     * @throws ConversionException if thrown by an underlying Converter
    246     */
    247    public <T> Object convert(final Object value, final Class<T> targetType) {
    248        final boolean nullValue = value == null;
    249        final Class<?> sourceType = nullValue ? null : value.getClass();
    250
    251        if (LOG.isDebugEnabled()) {
    252            if (nullValue) {
    253                LOG.debug("Convert null value to type '" + targetType.getName() + "'");
    254            } else {
    255                LOG.debug("Convert type '" + sourceType.getName() + "' value '" + value + "' to type '" + targetType.getName() + "'");
    256            }
    257        }
    258
    259        Object converted = value;
    260        final Converter<T> converter = lookup(sourceType, targetType);
    261        if (converter != null) {
    262            if (LOG.isTraceEnabled()) {
    263                LOG.trace("  Using converter " + converter);
    264            }
    265            converted = converter.convert(targetType, value);
    266        }
    267        if (String.class.equals(targetType) && converted != null && !(converted instanceof String)) {
    268
    269            // NOTE: For backwards compatibility, if the Converter
    270            // doesn't handle conversion-->String then
    271            // use the registered String Converter
    272            final Converter<String> strConverter = lookup(String.class);
    273            if (strConverter != null) {
    274                if (LOG.isTraceEnabled()) {
    275                    LOG.trace("  Using converter " + converter);
    276                }
    277                converted = strConverter.convert(String.class, converted);
    278            }
    279
    280            // If the object still isn't a String, use toString() method
    281            if (converted != null && !(converted instanceof String)) {
    282                converted = converted.toString();
    283            }
    284
    285        }
    286        return converted;
    287    }
    288
    289    /**
    290     * Delegates to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
    291     *
    292     * @param <R> the type of the class for the return value.
    293     * @param value Value to be converted (may be null)
    294     * @param clazz Java class to be converted to (must not be null)
    295     * @return The converted value or null if value is null
    296     * @see ConvertUtilsBean#convert(String[], Class)
    297     */
    298    public <R> Object convert(final String value, final Class<R> clazz) {
    299        return convert((Object) value, clazz);
    300    }
    301
    302    /**
    303     * Delegates to the new {@link ConvertUtilsBean#convert(Object, Class)} method.
    304     *
    305     * @param <T> the type of the class for the return value.
    306     * @param value Array of values to be converted
    307     * @param clazz Java array or element class to be converted to (must not be null)
    308     * @return The converted value
    309     * @see ConvertUtilsBean#convert(String[], Class)
    310     */
    311    public <T> Object convert(final String[] value, final Class<T> clazz) {
    312        return convert((Object) value, clazz);
    313    }
    314
    315    private <T> Object convert(final String[] values, final Class<T> type, final Converter<T> converter) {
    316        if (LOG.isTraceEnabled()) {
    317            LOG.trace("  Using converter " + converter);
    318        }
    319        final Object array = Array.newInstance(type, values.length);
    320        for (int i = 0; i < values.length; i++) {
    321            Array.set(array, i, converter.convert(type, values[i]));
    322        }
    323        return array;
    324    }
    325
    326    /**
    327     * Deregisters all registered {@link Converter}s, and re-establish the standard Converters.
    328     */
    329    public void deregister() {
    330
    331        converters.clear();
    332
    333        registerPrimitives(false);
    334        registerStandard(false, false);
    335        registerOther(true);
    336        registerArrays(false, 0);
    337        register(BigDecimal.class, new BigDecimalConverter());
    338        register(BigInteger.class, new BigIntegerConverter());
    339    }
    340
    341    /**
    342     * Remove any registered {@link Converter} for the specified destination {@code Class}.
    343     *
    344     * @param clazz Class for which to remove a registered Converter
    345     */
    346    public void deregister(final Class<?> clazz) {
    347        converters.remove(clazz);
    348    }
    349
    350    /**
    351     * Looks up and return any registered {@link Converter} for the specified source and destination class; if there is no registered Converter, return
    352     * {@code null}.
    353     *
    354     * @param <T>        The converter type.
    355     * @param sourceType Class of the value being converted
    356     * @param targetType Class of the value to be converted to
    357     * @return The registered {@link Converter} or {@code null} if not found
    358     */
    359    public <T> Converter<T> lookup(final Class<?> sourceType, final Class<T> targetType) {
    360        Objects.requireNonNull(targetType, "targetType");
    361        if (sourceType == null) {
    362            return lookup(targetType);
    363        }
    364        Converter converter = null;
    365        // Convert --> String
    366        if (targetType == String.class) {
    367            converter = lookup(sourceType);
    368            if (converter == null && (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType))) {
    369                converter = lookup(String[].class);
    370            }
    371            if (converter == null) {
    372                converter = lookup(String.class);
    373            }
    374            return converter;
    375        }
    376
    377        // Convert --> String array
    378        if (targetType == String[].class) {
    379            if (sourceType.isArray() || Collection.class.isAssignableFrom(sourceType)) {
    380                converter = lookup(sourceType);
    381            }
    382            if (converter == null) {
    383                converter = lookup(String[].class);
    384            }
    385            return converter;
    386        }
    387
    388        return lookup(targetType);
    389
    390    }
    391
    392    /**
    393     * Looks up and return any registered {@link Converter} for the specified destination class; if there is no registered Converter, return {@code null}.
    394     *
    395     * @param <T>   The converter type.
    396     * @param clazz Class for which to return a registered Converter
    397     * @return The registered {@link Converter} or {@code null} if not found
    398     */
    399    @SuppressWarnings("unchecked")
    400    public <T> Converter<T> lookup(final Class<T> clazz) {
    401        return (Converter<T>) converters.get(clazz);
    402    }
    403
    404    /**
    405     * Registers the provided converters with the specified defaults.
    406     *
    407     * @param throwException   {@code true} if the converters should throw an exception when a conversion error occurs, otherwise {@code false} if a default
    408     *                         value should be used.
    409     * @param defaultNull      {@code true}if the <em>standard</em> converters (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)}) should use a
    410     *                         default value of {@code null</code>, otherwise <code>false}.
    411     * N.B. This values is ignored if {@code throwException</code> is <code>true}
    412     * @param defaultArraySize The size of the default array value for array converters
    413     * (N.B. This values is ignored if {@code throwException</code> is <code>true}). Specifying a value less than zero causes a {@code null} value to be used
    414     * for the default.
    415     */
    416    public void register(final boolean throwException, final boolean defaultNull, final int defaultArraySize) {
    417        registerPrimitives(throwException);
    418        registerStandard(throwException, defaultNull);
    419        registerOther(throwException);
    420        registerArrays(throwException, defaultArraySize);
    421    }
    422
    423    /** Strictly for convenience since it has same parameter order as Map.put */
    424    private <T> void register(final Class<?> clazz, final Converter<T> converter) {
    425        register(new ConverterFacade<>(converter), clazz);
    426    }
    427
    428    /**
    429     * Registers a custom {@link Converter} for the specified destination {@code Class}, replacing any previously registered Converter.
    430     *
    431     * @param converter Converter to be registered
    432     * @param clazz     Destination class for conversions performed by this Converter
    433     */
    434    public void register(final Converter converter, final Class<?> clazz) {
    435        converters.put(clazz, converter);
    436    }
    437
    438    /**
    439     * Registers a new ArrayConverter with the specified element delegate converter that returns a default array of the specified size in the event of
    440     * conversion errors.
    441     *
    442     * @param componentType      The component type of the array
    443     * @param componentConverter The converter to delegate to for the array elements
    444     * @param throwException     Whether a conversion exception should be thrown or a default value used in the event of a conversion error
    445     * @param defaultArraySize   The size of the default array
    446     */
    447    private <T> void registerArrayConverter(final Class<T> componentType, final Converter<T> componentConverter, final boolean throwException,
    448            final int defaultArraySize) {
    449        final Class<T[]> arrayType = (Class<T[]>) Array.newInstance(componentType, 0).getClass();
    450        final Converter<T[]> arrayConverter;
    451        if (throwException) {
    452            arrayConverter = new ArrayConverter<>(arrayType, componentConverter);
    453        } else {
    454            arrayConverter = new ArrayConverter<>(arrayType, componentConverter, defaultArraySize);
    455        }
    456        register(arrayType, arrayConverter);
    457    }
    458
    459    /**
    460     * Registers array converters.
    461     *
    462     * @param throwException   {@code true} if the converters should throw an exception when a conversion error occurs, otherwise {@code false} if a default
    463     *                         value should be used.
    464     * @param defaultArraySize The size of the default array value for array converters (N.B. This values is ignored if
    465     *                         {@code throwException</code> is <code>true}). Specifying a value less than zero causes a {@code null} value to be used for the
    466     *                         default.
    467     */
    468    private void registerArrays(final boolean throwException, final int defaultArraySize) {
    469        // @formatter:off
    470
    471        // Primitives
    472        registerArrayConverter(Boolean.TYPE,   new BooleanConverter(),   throwException, defaultArraySize);
    473        registerArrayConverter(Byte.TYPE,      new ByteConverter(),      throwException, defaultArraySize);
    474        registerArrayConverter(Character.TYPE, new CharacterConverter(), throwException, defaultArraySize);
    475        registerArrayConverter(Double.TYPE,    new DoubleConverter(),    throwException, defaultArraySize);
    476        registerArrayConverter(Float.TYPE,     new FloatConverter(),     throwException, defaultArraySize);
    477        registerArrayConverter(Integer.TYPE,   new IntegerConverter(),   throwException, defaultArraySize);
    478        registerArrayConverter(Long.TYPE,      new LongConverter(),      throwException, defaultArraySize);
    479        registerArrayConverter(Short.TYPE,     new ShortConverter(),     throwException, defaultArraySize);
    480
    481        // Standard
    482        registerArrayConverter(BigDecimal.class, new BigDecimalConverter(), throwException, defaultArraySize);
    483        registerArrayConverter(BigInteger.class, new BigIntegerConverter(), throwException, defaultArraySize);
    484        registerArrayConverter(Boolean.class,    new BooleanConverter(),    throwException, defaultArraySize);
    485        registerArrayConverter(Byte.class,       new ByteConverter(),       throwException, defaultArraySize);
    486        registerArrayConverter(Character.class,  new CharacterConverter(),  throwException, defaultArraySize);
    487        registerArrayConverter(Double.class,     new DoubleConverter(),     throwException, defaultArraySize);
    488        registerArrayConverter(Float.class,      new FloatConverter(),      throwException, defaultArraySize);
    489        registerArrayConverter(Integer.class,    new IntegerConverter(),    throwException, defaultArraySize);
    490        registerArrayConverter(Long.class,       new LongConverter(),       throwException, defaultArraySize);
    491        registerArrayConverter(Short.class,      new ShortConverter(),      throwException, defaultArraySize);
    492        registerArrayConverter(String.class,     new StringConverter(),     throwException, defaultArraySize);
    493
    494        // Other
    495        registerArrayConverter(Class.class,          new ClassConverter(),         throwException, defaultArraySize);
    496        registerArrayConverter(Color.class,          new ColorConverter(),         throwException, defaultArraySize);
    497        registerArrayConverter(Enum.class,           new EnumConverter(),          throwException, defaultArraySize);
    498        registerArrayConverter(java.util.Date.class, new DateConverter(),          throwException, defaultArraySize);
    499        registerArrayConverter(Calendar.class,       new CalendarConverter(),      throwException, defaultArraySize);
    500        registerArrayConverter(Dimension.class,      new DimensionConverter(),     throwException, defaultArraySize);
    501        registerArrayConverter(File.class,           new FileConverter(),          throwException, defaultArraySize);
    502        registerArrayConverter(InetAddress.class,    new InetAddressConverter(),   throwException, defaultArraySize);
    503        registerArrayConverter(Path.class,           new PathConverter(),          throwException, defaultArraySize);
    504        registerArrayConverter(java.sql.Date.class,  new SqlDateConverter(),       throwException, defaultArraySize);
    505        registerArrayConverter(java.sql.Time.class,  new SqlTimeConverter(),       throwException, defaultArraySize);
    506        registerArrayConverter(Timestamp.class,      new SqlTimestampConverter(),  throwException, defaultArraySize);
    507        registerArrayConverter(URL.class,            new URLConverter(),           throwException, defaultArraySize);
    508        registerArrayConverter(URI.class,            new URIConverter(),           throwException, defaultArraySize);
    509        registerArrayConverter(UUID.class,           new UUIDConverter(),          throwException, defaultArraySize);
    510        registerArrayConverter(LocalDate.class,      new LocalDateConverter(),     throwException, defaultArraySize);
    511        registerArrayConverter(LocalDateTime.class,  new LocalDateTimeConverter(), throwException, defaultArraySize);
    512        registerArrayConverter(LocalTime.class,      new LocalTimeConverter(),     throwException, defaultArraySize);
    513        registerArrayConverter(Locale.class,         new LocaleConverter(),        throwException, defaultArraySize);
    514        registerArrayConverter(OffsetDateTime.class, new OffsetDateTimeConverter(),throwException, defaultArraySize);
    515        registerArrayConverter(OffsetTime.class,     new OffsetTimeConverter(),    throwException, defaultArraySize);
    516        registerArrayConverter(ZonedDateTime.class,  new ZonedDateTimeConverter(), throwException, defaultArraySize);
    517        registerArrayConverter(Duration.class,       new DurationConverter(),      throwException, defaultArraySize);
    518        registerArrayConverter(MonthDay.class,       new MonthDayConverter(),      throwException, defaultArraySize);
    519        registerArrayConverter(Pattern.class,        new PatternConverter(),       throwException, defaultArraySize);
    520        registerArrayConverter(Period.class,         new PeriodConverter(),        throwException, defaultArraySize);
    521        registerArrayConverter(Point.class,          new PointConverter(),         throwException, defaultArraySize);
    522        registerArrayConverter(Year.class,           new YearConverter(),          throwException, defaultArraySize);
    523        registerArrayConverter(YearMonth.class,      new YearMonthConverter(),     throwException, defaultArraySize);
    524        registerArrayConverter(ZoneId.class,         new ZoneIdConverter(),        throwException, defaultArraySize);
    525        registerArrayConverter(ZoneOffset.class,     new ZoneOffsetConverter(),    throwException, defaultArraySize);
    526        // @formatter:on
    527    }
    528
    529    /**
    530     * Registers the converters for other types.
    531     * </p>
    532     * This method registers the following converters:
    533     * <ul>
    534     * <li>{@code Class.class} - {@link ClassConverter}</li>
    535     * <li>{@code Enum.class} - {@link EnumConverter}</li>
    536     * <li>{@code java.util.Date.class} - {@link DateConverter}</li>
    537     * <li>{@code java.util.Calendar.class} - {@link CalendarConverter}</li>
    538     * <li>{@code File.class} - {@link FileConverter}</li>
    539     * <li>{@code Path.class} - {@link PathConverter}</li>
    540     * <li>{@code java.sql.Date.class} - {@link SqlDateConverter}</li>
    541     * <li>{@code java.sql.Time.class} - {@link SqlTimeConverter}</li>
    542     * <li>{@code java.sql.Timestamp.class} - {@link SqlTimestampConverter}</li>
    543     * <li>{@code URL.class} - {@link URLConverter}</li>
    544     * <li>{@code URI.class} - {@link URIConverter}</li>
    545     * <li>{@code UUID.class} - {@link UUIDConverter}</li>
    546     * <li>{@code LocalDate.class} - {@link LocalDateConverter}</li>
    547     * <li>{@code LocalDateTime.class} - {@link LocalDateTimeConverter}</li>
    548     * <li>{@code LocalTime.class} - {@link LocalTimeConverter}</li>
    549     * <li>{@code OffsetDateTime.class} - {@link OffsetDateTimeConverter}</li>
    550     * <li>{@code OffsetTime.class} - {@link OffsetTimeConverter}</li>
    551     * <li>{@code ZonedDateTime.class} - {@link ZonedDateTimeConverter}</li>
    552     * <li>{@code Duration.class} - {@link DurationConverter}</li>
    553     * <li>{@code MonthDay.class} - {@link MonthDayConverter}</li>
    554     * <li>{@code Period.class} - {@link PeriodConverter}</li>
    555     * <li>{@code Year.class} - {@link YearConverter}</li>
    556     * <li>{@code YearMonth.class} - {@link YearMonthConverter}</li>
    557     * <li>{@code ZoneId.class} - {@link ZoneIdConverter}</li>
    558     * <li>{@code ZoneOffset.class} - {@link ZoneOffsetConverter}</li>
    559     * </ul>
    560     *
    561     * @param throwException {@code true} if the converters should throw an exception when a conversion error occurs, otherwise <code> {@code false} if a
    562     *                       default value should be used.
    563     */
    564    private void registerOther(final boolean throwException) {
    565        // @formatter:off
    566        register(Class.class,          throwException ? new ClassConverter<>()        : new ClassConverter<>(null));
    567        register(Color.class,          throwException ? new ColorConverter()          : new ColorConverter(null));
    568        register(Enum.class,           throwException ? new EnumConverter()           : new EnumConverter(null));
    569        register(java.util.Date.class, throwException ? new DateConverter()           : new DateConverter(null));
    570        register(Dimension.class,      throwException ? new DimensionConverter()      : new DimensionConverter(null));
    571        register(Calendar.class,       throwException ? new CalendarConverter()       : new CalendarConverter(null));
    572        register(File.class,           throwException ? new FileConverter()           : new FileConverter(null));
    573        register(InetAddress.class,    throwException ? new InetAddressConverter()    : new InetAddressConverter(null));
    574        register(Path.class,           throwException ? new PathConverter()           : new PathConverter(null));
    575        register(java.sql.Date.class,  throwException ? new SqlDateConverter()        : new SqlDateConverter(null));
    576        register(java.sql.Time.class,  throwException ? new SqlTimeConverter()        : new SqlTimeConverter(null));
    577        register(Timestamp.class,      throwException ? new SqlTimestampConverter()   : new SqlTimestampConverter(null));
    578        register(URL.class,            throwException ? new URLConverter()            : new URLConverter(null));
    579        register(URI.class,            throwException ? new URIConverter()            : new URIConverter(null));
    580        register(UUID.class,           throwException ? new UUIDConverter()           : new UUIDConverter(null));
    581        register(LocalDate.class,      throwException ? new LocalDateConverter()      : new LocalDateConverter(null));
    582        register(LocalDateTime.class,  throwException ? new LocalDateTimeConverter()  : new LocalDateTimeConverter(null));
    583        register(LocalTime.class,      throwException ? new LocalTimeConverter()      : new LocalTimeConverter(null));
    584        register(Locale.class,         throwException ? new LocaleConverter()         : new LocaleConverter(null));
    585        register(OffsetDateTime.class, throwException ? new OffsetDateTimeConverter() : new OffsetDateTimeConverter(null));
    586        register(OffsetTime.class,     throwException ? new OffsetTimeConverter()     : new OffsetTimeConverter(null));
    587        register(ZonedDateTime.class,  throwException ? new ZonedDateTimeConverter()  : new ZonedDateTimeConverter(null));
    588        register(Duration.class,       throwException ? new DurationConverter()       : new DurationConverter(null));
    589        register(MonthDay.class,       throwException ? new MonthDayConverter()       : new MonthDayConverter(null));
    590        register(Pattern.class,        throwException ? new PatternConverter()        : new PatternConverter(null));
    591        register(Period.class,         throwException ? new PeriodConverter()         : new PeriodConverter(null));
    592        register(Point.class,          throwException ? new PointConverter()          : new PointConverter(null));
    593        register(Year.class,           throwException ? new YearConverter()           : new YearConverter(null));
    594        register(YearMonth.class,      throwException ? new YearMonthConverter()      : new YearMonthConverter(null));
    595        register(ZoneId.class,         throwException ? new ZoneIdConverter()         : new ZoneIdConverter(null));
    596        register(ZoneOffset.class,     throwException ? new ZoneOffsetConverter()     : new ZoneOffsetConverter(null));
    597        // @formatter:on
    598    }
    599
    600    /**
    601     * Registers the converters for primitive types.
    602     * </p>
    603     * This method registers the following converters:
    604     * <ul>
    605     * <li>{@code Boolean.TYPE} - {@link BooleanConverter}</li>
    606     * <li>{@code Byte.TYPE} - {@link ByteConverter}</li>
    607     * <li>{@code Character.TYPE} - {@link CharacterConverter}</li>
    608     * <li>{@code Double.TYPE} - {@link DoubleConverter}</li>
    609     * <li>{@code Float.TYPE} - {@link FloatConverter}</li>
    610     * <li>{@code Integer.TYPE} - {@link IntegerConverter}</li>
    611     * <li>{@code Long.TYPE} - {@link LongConverter}</li>
    612     * <li>{@code Short.TYPE} - {@link ShortConverter}</li>
    613     * </ul>
    614     *
    615     * @param throwException {@code true} if the converters should throw an exception when a conversion error occurs, otherwise <code> {@code false} if a
    616     *                       default value should be used.
    617     */
    618    private void registerPrimitives(final boolean throwException) {
    619        register(Boolean.TYPE, throwException ? new BooleanConverter() : new BooleanConverter(Boolean.FALSE));
    620        register(Byte.TYPE, throwException ? new ByteConverter() : new ByteConverter(ZERO));
    621        register(Character.TYPE, throwException ? new CharacterConverter() : new CharacterConverter(SPACE));
    622        register(Double.TYPE, throwException ? new DoubleConverter() : new DoubleConverter(ZERO));
    623        register(Float.TYPE, throwException ? new FloatConverter() : new FloatConverter(ZERO));
    624        register(Integer.TYPE, throwException ? new IntegerConverter() : new IntegerConverter(ZERO));
    625        register(Long.TYPE, throwException ? new LongConverter() : new LongConverter(ZERO));
    626        register(Short.TYPE, throwException ? new ShortConverter() : new ShortConverter(ZERO));
    627    }
    628
    629    /**
    630     * Registers the converters for standard types.
    631     * </p>
    632     * This method registers the following converters:
    633     * <ul>
    634     * <li>{@code BigDecimal.class} - {@link BigDecimalConverter}</li>
    635     * <li>{@code BigInteger.class} - {@link BigIntegerConverter}</li>
    636     * <li>{@code Boolean.class} - {@link BooleanConverter}</li>
    637     * <li>{@code Byte.class} - {@link ByteConverter}</li>
    638     * <li>{@code Character.class} - {@link CharacterConverter}</li>
    639     * <li>{@code Double.class} - {@link DoubleConverter}</li>
    640     * <li>{@code Float.class} - {@link FloatConverter}</li>
    641     * <li>{@code Integer.class} - {@link IntegerConverter}</li>
    642     * <li>{@code Long.class} - {@link LongConverter}</li>
    643     * <li>{@code Short.class} - {@link ShortConverter}</li>
    644     * <li>{@code String.class} - {@link StringConverter}</li>
    645     * </ul>
    646     *
    647     * @param throwException {@code true} if the converters should throw an exception when a conversion error occurs, otherwise <code>
    648     *                       {@code false} if a default value should be used.
    649     * @param defaultNull {@code true}if the <em>standard</em> converters
    650     * (see {@link ConvertUtilsBean#registerStandard(boolean, boolean)})
    651     * should use a default value of {@code null</code>, otherwise <code>false}.
    652     * N.B. This values is ignored if {@code throwException</code> is <code>true}
    653     */
    654    private void registerStandard(final boolean throwException, final boolean defaultNull) {
    655
    656        final Number defaultNumber = defaultNull ? null : ZERO;
    657        final BigDecimal bigDecDeflt = defaultNull ? null : new BigDecimal("0.0");
    658        final BigInteger bigIntDeflt = defaultNull ? null : new BigInteger("0");
    659        final Boolean booleanDefault = defaultNull ? null : Boolean.FALSE;
    660        final Character charDefault = defaultNull ? null : SPACE;
    661        final String stringDefault = defaultNull ? null : "";
    662
    663        register(BigDecimal.class, throwException ? new BigDecimalConverter() : new BigDecimalConverter(bigDecDeflt));
    664        register(BigInteger.class, throwException ? new BigIntegerConverter() : new BigIntegerConverter(bigIntDeflt));
    665        register(Boolean.class, throwException ? new BooleanConverter() : new BooleanConverter(booleanDefault));
    666        register(Byte.class, throwException ? new ByteConverter() : new ByteConverter(defaultNumber));
    667        register(Character.class, throwException ? new CharacterConverter() : new CharacterConverter(charDefault));
    668        register(Double.class, throwException ? new DoubleConverter() : new DoubleConverter(defaultNumber));
    669        register(Float.class, throwException ? new FloatConverter() : new FloatConverter(defaultNumber));
    670        register(Integer.class, throwException ? new IntegerConverter() : new IntegerConverter(defaultNumber));
    671        register(Long.class, throwException ? new LongConverter() : new LongConverter(defaultNumber));
    672        register(Short.class, throwException ? new ShortConverter() : new ShortConverter(defaultNumber));
    673        register(String.class, throwException ? new StringConverter() : new StringConverter(stringDefault));
    674
    675    }
    676}