    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.configuration2;
    019
    020import java.awt.Color;
    021import java.math.BigDecimal;
    022import java.math.BigInteger;
    023import java.net.URI;
    024import java.net.URL;
    025import java.util.ArrayList;
    026import java.util.Calendar;
    027import java.util.Date;
    028import java.util.Iterator;
    029import java.util.List;
    030import java.util.Locale;
    031import java.util.NoSuchElementException;
    032
    033import org.apache.commons.configuration2.convert.ConversionHandler;
    034import org.apache.commons.configuration2.convert.DefaultConversionHandler;
    035import org.apache.commons.configuration2.ex.ConversionException;
    036import org.apache.commons.lang3.ArrayUtils;
    037import org.apache.commons.lang3.StringUtils;
    038
    039/**
    040 * Decorator providing additional getters for any Configuration. This extended
    041 * Configuration supports more types:
    042 * <ul>
    043 *   <li>{@link java.net.URL}</li>
    044 *   <li>{@link java.util.Locale}</li>
    045 *   <li>{@link java.util.Date}</li>
    046 *   <li>{@link java.util.Calendar}</li>
    047 *   <li>{@link java.awt.Color}</li>
    048 *   <li>{@link java.net.InetAddress}</li>
    049 *   <li>{@code javax.mail.internet.InternetAddress} (requires Javamail in the classpath)</li>
    050 *   <li>{@link java.lang.Enum} (Java 5 enumeration types)</li>
    051 * </ul>
    052 *
    053 * Lists and arrays are available for all types.<br>
    054 * Note that this class is only a thin wrapper over functionality already
    055 * provided by {@link AbstractConfiguration}. Basically, the generic
    056 * {@code get()}, and {@code getCollection()} methods are
    057 * used to actually perform data conversions.
    058 *
    059 * <p><strong>Example</strong></p>
    060 *
    061 * Configuration file {@code config.properties}:
    062 * <pre>
    063 * title.color = #0000FF
    064 * remote.host = 192.168.0.53
    065 * default.locales = fr,en,de
    066 * email.contact = ebourg@apache.org, tester@test.org
    067 * </pre>
    068 *
    069 * Usage:
    070 *
    071 * <pre>
    072 * DataConfiguration config = new DataConfiguration(new PropertiesConfiguration("config.properties"));
    073 *
    074 * // retrieve a property using a specialized getter
    075 * Color color = config.getColor("title.color");
    076 *
    077 * // retrieve a property using a generic getter
    078 * InetAddress host = (InetAddress) config.get(InetAddress.class, "remote.host");
    079 * Locale[] locales = (Locale[]) config.getArray(Locale.class, "default.locales");
    080 * List contacts = config.getList(InternetAddress.class, "email.contact");
    081 * </pre>
    082 *
    083 * <p><strong>Dates</strong></p>
    084 *
    085 * Date objects are expected to be formatted with the pattern {@code yyyy-MM-dd HH:mm:ss}.
    086 * This default format can be changed by specifying another format in the
    087 * getters, or by putting a date format in the configuration under the key
    088 * {@code org.apache.commons.configuration.format.date}. Alternatively, the
    089 * date format can also be specified via the {@code ConversionHandler} used
    090 * by a configuration instance:
    091 *
    092 * <pre>
    093 * DefaultConversionHandler handler = new DefaultConversionHandler();
    094 * handler.setDateFormat("mm/dd/yyyy");
    095 * config.setConversionHandler(handler);
    096 * </pre>
    097 *
    098 * @since 1.1
    099 */
    100public class DataConfiguration extends AbstractConfiguration
    101{
    102    /** The key of the property storing the user defined date format. */
    103    public static final String DATE_FORMAT_KEY = "org.apache.commons.configuration.format.date";
    104
    105    /** The default format for dates. */
    106    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    107
    108    /** Empty array constant. */
    109    private static final URL[] EMPTY_URL_ARRAY = new URL[0];
    110
    111    /** Empty array constant. */
    112    private static final URI[] EMPTY_URI_ARRAY = new URI[0];
    113
    114    /** Empty array constant. */
    115    private static final Locale[] EMPTY_LOCALE_ARRAY = new Locale[0];
    116
    117    /** Empty array constant. */
    118    private static final Date[] EMPTY_DATE_ARRAY = new Date[0];
    119
    120    /** Empty array constant. */
    121    private static final Color[] EMPTY_COLOR_ARRAY = new Color[0];
    122
    123    /** Empty array constant. */
    124    private static final Calendar[] EMPTY_CALENDARD_ARRAY = new Calendar[0];
    125
    126    /** Empty array constant. */
    127    private static final BigInteger[] EMPTY_BIG_INTEGER_ARRAY = new BigInteger[0];
    128
    129    /** Empty array constant. */
    130    private static final BigDecimal[] EMPTY_BIG_DECIMAL_ARRAY = new BigDecimal[0];
    131
    132    /** Stores temporary date formats. */
    133    private static final ThreadLocal<String> TEMP_DATE_FORMAT = new ThreadLocal<>();
    134
    135    /** Stores the wrapped configuration.*/
    136    private final Configuration configuration;
    137
    138    /** A special conversion handler object used by this configuration. */
    139    private final ConversionHandler dataConversionHandler;
    140
    141    /**
    142     * Creates a new instance of {@code DataConfiguration} and sets the
    143     * wrapped configuration.
    144     *
    145     * @param configuration the wrapped configuration
    146     */
    147    public DataConfiguration(final Configuration configuration)
    148    {
    149        this.configuration = configuration;
    150        dataConversionHandler = new DataConversionHandler();
    151    }
    152
    153    /**
    154     * Return the configuration decorated by this DataConfiguration.
    155     *
    156     * @return the wrapped configuration
    157     */
    158    public Configuration getConfiguration()
    159    {
    160        return configuration;
    161    }
    162
    163    /**
    164     * {@inheritDoc} This implementation returns the special conversion handler
    165     * used by this configuration instance.
    166     */
    167    @Override
    168    public ConversionHandler getConversionHandler()
    169    {
    170        return dataConversionHandler;
    171    }
    172
    173    @Override
    174    protected Object getPropertyInternal(final String key)
    175    {
    176        return configuration.getProperty(key);
    177    }
    178
    179    @Override
    180    protected void addPropertyInternal(final String key, final Object obj)
    181    {
    182        configuration.addProperty(key, obj);
    183    }
    184
    185    @Override
    186    protected void addPropertyDirect(final String key, final Object value)
    187    {
    188        if (configuration instanceof AbstractConfiguration)
    189        {
    190            ((AbstractConfiguration) configuration).addPropertyDirect(key, value);
    191        }
    192        else
    193        {
    194            configuration.addProperty(key, value);
    195        }
    196    }
    197
    198    @Override
    199    protected boolean isEmptyInternal()
    200    {
    201        return configuration.isEmpty();
    202    }
    203
    204    @Override
    205    protected boolean containsKeyInternal(final String key)
    206    {
    207        return configuration.containsKey(key);
    208    }
    209
    210    @Override
    211    protected void clearPropertyDirect(final String key)
    212    {
    213        configuration.clearProperty(key);
    214    }
    215
    216    @Override
    217    protected void setPropertyInternal(final String key, final Object value)
    218    {
    219        configuration.setProperty(key, value);
    220    }
    221
    222    @Override
    223    protected Iterator<String> getKeysInternal()
    224    {
    225        return configuration.getKeys();
    226    }
    227
    228    /**
    229     * Get a list of Boolean objects associated with the given
    230     * configuration key. If the key doesn't map to an existing object
    231     * an empty list is returned.
    232     *
    233     * @param key The configuration key.
    234     * @return The associated Boolean list if the key is found.
    235     *
    236     * @throws ConversionException is thrown if the key maps to an
    237     *         object that is not a list of booleans.
    238     */
    239    public List<Boolean> getBooleanList(final String key)
    240    {
    241        return getBooleanList(key, new ArrayList<Boolean>());
    242    }
    243
    244    /**
    245     * Get a list of Boolean objects associated with the given
    246     * configuration key. If the key doesn't map to an existing object,
    247     * the default value is returned.
    248     *
    249     * @param key The configuration key.
    250     * @param defaultValue The default value.
    251     * @return The associated List of Booleans.
    252     *
    253     * @throws ConversionException is thrown if the key maps to an
    254     *         object that is not a list of booleans.
    255     */
    256    public List<Boolean> getBooleanList(final String key, final List<Boolean> defaultValue)
    257    {
    258         return getList(Boolean.class, key, defaultValue);
    259    }
    260
    261    /**
    262     * Get an array of boolean primitives associated with the given
    263     * configuration key. If the key doesn't map to an existing object
    264     * an empty array is returned.
    265     *
    266     * @param key The configuration key.
    267     * @return The associated boolean array if the key is found.
    268     *
    269     * @throws ConversionException is thrown if the key maps to an
    270     *         object that is not a list of booleans.
    271     */
    272    public boolean[] getBooleanArray(final String key)
    273    {
    274        return (boolean[]) getArray(Boolean.TYPE, key);
    275    }
    276
    277    /**
    278     * Get an array of boolean primitives associated with the given
    279     * configuration key. If the key doesn't map to an existing object,
    280     * the default value is returned.
    281     *
    282     * @param key          The configuration key.
    283     * @param defaultValue The default value.
    284     * @return The associated boolean array if the key is found.
    285     *
    286     * @throws ConversionException is thrown if the key maps to an
    287     *         object that is not a list of booleans.
    288     */
    289    public boolean[] getBooleanArray(final String key, final boolean... defaultValue)
    290    {
    291        return get(boolean[].class, key, defaultValue);
    292    }
    293
    294    /**
    295     * Get a list of Byte objects associated with the given configuration key.
    296     * If the key doesn't map to an existing object an empty list is returned.
    297     *
    298     * @param key The configuration key.
    299     * @return The associated Byte list if the key is found.
    300     *
    301     * @throws ConversionException is thrown if the key maps to an
    302     *         object that is not a list of bytes.
    303     */
    304    public List<Byte> getByteList(final String key)
    305    {
    306        return getByteList(key, new ArrayList<Byte>());
    307    }
    308
    309    /**
    310     * Get a list of Byte objects associated with the given configuration key.
    311     * If the key doesn't map to an existing object, the default value is
    312     * returned.
    313     *
    314     * @param key The configuration key.
    315     * @param defaultValue The default value.
    316     * @return The associated List of Bytes.
    317     *
    318     * @throws ConversionException is thrown if the key maps to an
    319     *         object that is not a list of bytes.
    320     */
    321    public List<Byte> getByteList(final String key, final List<Byte> defaultValue)
    322    {
    323        return getList(Byte.class, key, defaultValue);
    324    }
    325
    326    /**
    327     * Get an array of byte primitives associated with the given
    328     * configuration key. If the key doesn't map to an existing object
    329     * an empty array is returned.
    330     *
    331     * @param key The configuration key.
    332     * @return The associated byte array if the key is found.
    333     *
    334     * @throws ConversionException is thrown if the key maps to an
    335     *         object that is not a list of bytes.
    336     */
    337    public byte[] getByteArray(final String key)
    338    {
    339        return getByteArray(key, ArrayUtils.EMPTY_BYTE_ARRAY);
    340    }
    341
    342    /**
    343     * Get an array of byte primitives associated with the given
    344     * configuration key. If the key doesn't map to an existing object
    345     * an empty array is returned.
    346     *
    347     * @param key The configuration key.
    348     * @param defaultValue the default value, which will be returned if the property is not found
    349     * @return The associated byte array if the key is found.
    350     *
    351     * @throws ConversionException is thrown if the key maps to an
    352     *         object that is not a list of bytes.
    353     */
    354    public byte[] getByteArray(final String key, final byte... defaultValue)
    355    {
    356        return get(byte[].class, key, defaultValue);
    357    }
    358
    359    /**
    360     * Get a list of Short objects associated with the given configuration key.
    361     * If the key doesn't map to an existing object an empty list is returned.
    362     *
    363     * @param key The configuration key.
    364     * @return The associated Short list if the key is found.
    365     *
    366     * @throws ConversionException is thrown if the key maps to an
    367     *         object that is not a list of shorts.
    368     */
    369    public List<Short> getShortList(final String key)
    370    {
    371        return getShortList(key, new ArrayList<Short>());
    372    }
    373
    374    /**
    375     * Get a list of Short objects associated with the given configuration key.
    376     * If the key doesn't map to an existing object, the default value is
    377     * returned.
    378     *
    379     * @param key The configuration key.
    380     * @param defaultValue The default value.
    381     * @return The associated List of Shorts.
    382     *
    383     * @throws ConversionException is thrown if the key maps to an
    384     *         object that is not a list of shorts.
    385     */
    386    public List<Short> getShortList(final String key, final List<Short> defaultValue)
    387    {
    388        return getList(Short.class, key, defaultValue);
    389    }
    390
    391    /**
    392     * Get an array of short primitives associated with the given
    393     * configuration key. If the key doesn't map to an existing object
    394     * an empty array is returned.
    395     *
    396     * @param key The configuration key.
    397     * @return The associated short array if the key is found.
    398     *
    399     * @throws ConversionException is thrown if the key maps to an
    400     *         object that is not a list of shorts.
    401     */
    402    public short[] getShortArray(final String key)
    403    {
    404        return getShortArray(key, ArrayUtils.EMPTY_SHORT_ARRAY);
    405    }
    406
    407    /**
    408     * Get an array of short primitives associated with the given
    409     * configuration key. If the key doesn't map to an existing object
    410     * an empty array is returned.
    411     *
    412     * @param key The configuration key.
    413     * @param defaultValue the default value, which will be returned if the property is not found
    414     * @return The associated short array if the key is found.
    415     *
    416     * @throws ConversionException is thrown if the key maps to an
    417     *         object that is not a list of shorts.
    418     */
    419    public short[] getShortArray(final String key, final short... defaultValue)
    420    {
    421        return get(short[].class, key, defaultValue);
    422    }
    423
    424    /**
    425     * Get a list of Integer objects associated with the given
    426     * configuration key. If the key doesn't map to an existing object
    427     * an empty list is returned.
    428     *
    429     * @param key The configuration key.
    430     * @return The associated Integer list if the key is found.
    431     *
    432     * @throws ConversionException is thrown if the key maps to an
    433     *         object that is not a list of integers.
    434     */
    435    public List<Integer> getIntegerList(final String key)
    436    {
    437        return getIntegerList(key, new ArrayList<Integer>());
    438    }
    439
    440    /**
    441     * Get a list of Integer objects associated with the given
    442     * configuration key. If the key doesn't map to an existing object,
    443     * the default value is returned.
    444     *
    445     * @param key The configuration key.
    446     * @param defaultValue The default value.
    447     * @return The associated List of Integers.
    448     *
    449     * @throws ConversionException is thrown if the key maps to an
    450     *         object that is not a list of integers.
    451     */
    452    public List<Integer> getIntegerList(final String key, final List<Integer> defaultValue)
    453    {
    454        return getList(Integer.class, key, defaultValue);
    455    }
    456
    457    /**
    458     * Get an array of int primitives associated with the given
    459     * configuration key. If the key doesn't map to an existing object
    460     * an empty array is returned.
    461     *
    462     * @param key The configuration key.
    463     * @return The associated int array if the key is found.
    464     *
    465     * @throws ConversionException is thrown if the key maps to an
    466     *         object that is not a list of integers.
    467     */
    468    public int[] getIntArray(final String key)
    469    {
    470        return getIntArray(key, ArrayUtils.EMPTY_INT_ARRAY);
    471    }
    472
    473    /**
    474     * Get an array of int primitives associated with the given
    475     * configuration key. If the key doesn't map to an existing object
    476     * an empty array is returned.
    477     *
    478     * @param key The configuration key.
    479     * @param defaultValue the default value, which will be returned if the property is not found
    480     * @return The associated int array if the key is found.
    481     *
    482     * @throws ConversionException is thrown if the key maps to an
    483     *         object that is not a list of integers.
    484     */
    485    public int[] getIntArray(final String key, final int... defaultValue)
    486    {
    487        return get(int[].class, key, defaultValue);
    488    }
    489
    490    /**
    491     * Get a list of Long objects associated with the given configuration key.
    492     * If the key doesn't map to an existing object an empty list is returned.
    493     *
    494     * @param key The configuration key.
    495     * @return The associated Long list if the key is found.
    496     *
    497     * @throws ConversionException is thrown if the key maps to an
    498     *         object that is not a list of longs.
    499     */
    500    public List<Long> getLongList(final String key)
    501    {
    502        return getLongList(key, new ArrayList<Long>());
    503    }
    504
    505    /**
    506     * Get a list of Long objects associated with the given configuration key.
    507     * If the key doesn't map to an existing object, the default value is
    508     * returned.
    509     *
    510     * @param key The configuration key.
    511     * @param defaultValue The default value.
    512     * @return The associated List of Longs.
    513     *
    514     * @throws ConversionException is thrown if the key maps to an
    515     *         object that is not a list of longs.
    516     */
    517    public List<Long> getLongList(final String key, final List<Long> defaultValue)
    518    {
    519        return getList(Long.class, key, defaultValue);
    520    }
    521
    522    /**
    523     * Get an array of long primitives associated with the given
    524     * configuration key. If the key doesn't map to an existing object
    525     * an empty array is returned.
    526     *
    527     * @param key The configuration key.
    528     * @return The associated long array if the key is found.
    529     *
    530     * @throws ConversionException is thrown if the key maps to an
    531     *         object that is not a list of longs.
    532     */
    533    public long[] getLongArray(final String key)
    534    {
    535        return getLongArray(key, ArrayUtils.EMPTY_LONG_ARRAY);
    536    }
    537
    538    /**
    539     * Get an array of long primitives associated with the given
    540     * configuration key. If the key doesn't map to an existing object
    541     * an empty array is returned.
    542     *
    543     * @param key The configuration key.
    544     * @param defaultValue the default value, which will be returned if the property is not found
    545     * @return The associated long array if the key is found.
    546     *
    547     * @throws ConversionException is thrown if the key maps to an
    548     *         object that is not a list of longs.
    549     */
    550    public long[] getLongArray(final String key, final long... defaultValue)
    551    {
    552        return get(long[].class, key, defaultValue);
    553    }
    554
    555    /**
    556     * Get a list of Float objects associated with the given configuration key.
    557     * If the key doesn't map to an existing object an empty list is returned.
    558     *
    559     * @param key The configuration key.
    560     * @return The associated Float list if the key is found.
    561     *
    562     * @throws ConversionException is thrown if the key maps to an
    563     *         object that is not a list of floats.
    564     */
    565    public List<Float> getFloatList(final String key)
    566    {
    567        return getFloatList(key, new ArrayList<Float>());
    568    }
    569
    570    /**
    571     * Get a list of Float objects associated with the given
    572     * configuration key. If the key doesn't map to an existing object,
    573     * the default value is returned.
    574     *
    575     * @param key The configuration key.
    576     * @param defaultValue The default value.
    577     * @return The associated List of Floats.
    578     *
    579     * @throws ConversionException is thrown if the key maps to an
    580     *         object that is not a list of floats.
    581     */
    582    public List<Float> getFloatList(final String key, final List<Float> defaultValue)
    583    {
    584        return getList(Float.class, key, defaultValue);
    585    }
    586
    587    /**
    588     * Get an array of float primitives associated with the given
    589     * configuration key. If the key doesn't map to an existing object
    590     * an empty array is returned.
    591     *
    592     * @param key The configuration key.
    593     * @return The associated float array if the key is found.
    594     *
    595     * @throws ConversionException is thrown if the key maps to an
    596     *         object that is not a list of floats.
    597     */
    598    public float[] getFloatArray(final String key)
    599    {
    600        return getFloatArray(key, ArrayUtils.EMPTY_FLOAT_ARRAY);
    601    }
    602
    603    /**
    604     * Get an array of float primitives associated with the given
    605     * configuration key. If the key doesn't map to an existing object
    606     * an empty array is returned.
    607     *
    608     * @param key The configuration key.
    609     * @param defaultValue the default value, which will be returned if the property is not found
    610     * @return The associated float array if the key is found.
    611     *
    612     * @throws ConversionException is thrown if the key maps to an
    613     *         object that is not a list of floats.
    614     */
    615    public float[] getFloatArray(final String key, final float... defaultValue)
    616    {
    617        return get(float[].class, key, defaultValue);
    618    }
    619
    620    /**
    621     * Get a list of Double objects associated with the given
    622     * configuration key. If the key doesn't map to an existing object
    623     * an empty list is returned.
    624     *
    625     * @param key The configuration key.
    626     * @return The associated Double list if the key is found.
    627     *
    628     * @throws ConversionException is thrown if the key maps to an
    629     *         object that is not a list of doubles.
    630     */
    631    public List<Double> getDoubleList(final String key)
    632    {
    633        return getDoubleList(key, new ArrayList<Double>());
    634    }
    635
    636    /**
    637     * Get a list of Double objects associated with the given
    638     * configuration key. If the key doesn't map to an existing object,
    639     * the default value is returned.
    640     *
    641     * @param key The configuration key.
    642     * @param defaultValue The default value.
    643     * @return The associated List of Doubles.
    644     *
    645     * @throws ConversionException is thrown if the key maps to an
    646     *         object that is not a list of doubles.
    647     */
    648    public List<Double> getDoubleList(final String key, final List<Double> defaultValue)
    649    {
    650        return getList(Double.class, key, defaultValue);
    651    }
    652
    653    /**
    654     * Get an array of double primitives associated with the given
    655     * configuration key. If the key doesn't map to an existing object
    656     * an empty array is returned.
    657     *
    658     * @param key The configuration key.
    659     * @return The associated double array if the key is found.
    660     *
    661     * @throws ConversionException is thrown if the key maps to an
    662     *         object that is not a list of doubles.
    663     */
    664    public double[] getDoubleArray(final String key)
    665    {
    666        return getDoubleArray(key, ArrayUtils.EMPTY_DOUBLE_ARRAY);
    667    }
    668
    669    /**
    670     * Get an array of double primitives associated with the given
    671     * configuration key. If the key doesn't map to an existing object
    672     * an empty array is returned.
    673     *
    674     * @param key The configuration key.
    675     * @param defaultValue the default value, which will be returned if the property is not found
    676     * @return The associated double array if the key is found.
    677     *
    678     * @throws ConversionException is thrown if the key maps to an
    679     *         object that is not a list of doubles.
    680     */
    681    public double[] getDoubleArray(final String key, final double... defaultValue)
    682    {
    683        return get(double[].class, key, defaultValue);
    684    }
    685
    686    /**
    687     * Get a list of BigIntegers associated with the given configuration key.
    688     * If the key doesn't map to an existing object an empty list is returned.
    689     *
    690     * @param key The configuration key.
    691     * @return The associated BigInteger list if the key is found.
    692     *
    693     * @throws ConversionException is thrown if the key maps to an
    694     *         object that is not a list of BigIntegers.
    695     */
    696    public List<BigInteger> getBigIntegerList(final String key)
    697    {
    698        return getBigIntegerList(key, new ArrayList<BigInteger>());
    699    }
    700
    701    /**
    702     * Get a list of BigIntegers associated with the given configuration key.
    703     * If the key doesn't map to an existing object, the default value is
    704     * returned.
    705     *
    706     * @param key The configuration key.
    707     * @param defaultValue The default value.
    708     * @return The associated List of BigIntegers.
    709     *
    710     * @throws ConversionException is thrown if the key maps to an
    711     *         object that is not a list of BigIntegers.
    712     */
    713    public List<BigInteger> getBigIntegerList(final String key, final List<BigInteger> defaultValue)
    714    {
    715        return getList(BigInteger.class, key, defaultValue);
    716    }
    717
    718    /**
    719     * Get an array of BigIntegers associated with the given
    720     * configuration key. If the key doesn't map to an existing object
    721     * an empty array is returned.
    722     *
    723     * @param key The configuration key.
    724     * @return The associated BigInteger array if the key is found.
    725     *
    726     * @throws ConversionException is thrown if the key maps to an
    727     *         object that is not a list of BigIntegers.
    728     */
    729    public BigInteger[] getBigIntegerArray(final String key)
    730    {
    731        return getBigIntegerArray(key, EMPTY_BIG_INTEGER_ARRAY);
    732    }
    733
    734    /**
    735     * Get an array of BigIntegers associated with the given
    736     * configuration key. If the key doesn't map to an existing object
    737     * an empty array is returned.
    738     *
    739     * @param key The configuration key.
    740     * @param defaultValue the default value, which will be returned if the property is not found
    741     * @return The associated BigInteger array if the key is found.
    742     *
    743     * @throws ConversionException is thrown if the key maps to an
    744     *         object that is not a list of BigIntegers.
    745     */
    746    public BigInteger[] getBigIntegerArray(final String key, final BigInteger... defaultValue)
    747    {
    748        return get(BigInteger[].class, key, defaultValue);
    749    }
    750
    751    /**
    752     * Get a list of BigDecimals associated with the given configuration key.
    753     * If the key doesn't map to an existing object an empty list is returned.
    754     *
    755     * @param key The configuration key.
    756     * @return The associated BigDecimal list if the key is found.
    757     *
    758     * @throws ConversionException is thrown if the key maps to an
    759     *         object that is not a list of BigDecimals.
    760     */
    761    public List<BigDecimal> getBigDecimalList(final String key)
    762    {
    763        return getBigDecimalList(key, new ArrayList<BigDecimal>());
    764    }
    765
    766    /**
    767     * Get a list of BigDecimals associated with the given configuration key.
    768     * If the key doesn't map to an existing object, the default value is
    769     * returned.
    770     *
    771     * @param key The configuration key.
    772     * @param defaultValue The default value.
    773     * @return The associated List of BigDecimals.
    774     *
    775     * @throws ConversionException is thrown if the key maps to an
    776     *         object that is not a list of BigDecimals.
    777     */
    778    public List<BigDecimal> getBigDecimalList(final String key, final List<BigDecimal> defaultValue)
    779    {
    780        return getList(BigDecimal.class, key, defaultValue);
    781    }
    782
    783    /**
    784     * Get an array of BigDecimals associated with the given
    785     * configuration key. If the key doesn't map to an existing object
    786     * an empty array is returned.
    787     *
    788     * @param key The configuration key.
    789     * @return The associated BigDecimal array if the key is found.
    790     *
    791     * @throws ConversionException is thrown if the key maps to an
    792     *         object that is not a list of BigDecimals.
    793     */
    794    public BigDecimal[] getBigDecimalArray(final String key)
    795    {
    796        return getBigDecimalArray(key, EMPTY_BIG_DECIMAL_ARRAY);
    797    }
    798
    799    /**
    800     * Get an array of BigDecimals associated with the given
    801     * configuration key. If the key doesn't map to an existing object
    802     * an empty array is returned.
    803     *
    804     * @param key The configuration key.
    805     * @param defaultValue the default value, which will be returned if the property is not found
    806     * @return The associated BigDecimal array if the key is found.
    807     *
    808     * @throws ConversionException is thrown if the key maps to an
    809     *         object that is not a list of BigDecimals.
    810     */
    811    public BigDecimal[] getBigDecimalArray(final String key, final BigDecimal... defaultValue)
    812    {
    813        return get(BigDecimal[].class, key, defaultValue);
    814    }
    815
    816    /**
    817     * Get an URI associated with the given configuration key.
    818     *
    819     * @param key The configuration key.
    820     * @return The associated URI.
    821     *
    822     * @throws ConversionException is thrown if the key maps to an
    823     *         object that is not an URI.
    824     */
    825    public URI getURI(final String key)
    826    {
    827        return get(URI.class, key);
    828    }
    829
    830    /**
    831     * Get an URI associated with the given configuration key.
    832     * If the key doesn't map to an existing object, the default value
    833     * is returned.
    834     *
    835     * @param key          The configuration key.
    836     * @param defaultValue The default value.
    837     * @return The associated URI.
    838     *
    839     * @throws ConversionException is thrown if the key maps to an
    840     *         object that is not an URI.
    841     */
    842    public URI getURI(final String key, final URI defaultValue)
    843    {
    844        return get(URI.class, key, defaultValue);
    845    }
    846
    847    /**
    848     * Get an array of URIs associated with the given configuration key.
    849     * If the key doesn't map to an existing object an empty array is returned.
    850     *
    851     * @param key The configuration key.
    852     * @return The associated URI array if the key is found.
    853     *
    854     * @throws ConversionException is thrown if the key maps to an
    855     *         object that is not a list of URIs.
    856     */
    857    public URI[] getURIArray(final String key)
    858    {
    859        return getURIArray(key, EMPTY_URI_ARRAY);
    860    }
    861
    862    /**
    863     * Get an array of URIs associated with the given configuration key.
    864     * If the key doesn't map to an existing object an empty array is returned.
    865     *
    866     * @param key The configuration key.
    867     * @param defaultValue the default value, which will be returned if the property is not found
    868     * @return The associated URI array if the key is found.
    869     *
    870     * @throws ConversionException is thrown if the key maps to an
    871     *         object that is not a list of URIs.
    872     */
    873    public URI[] getURIArray(final String key, final URI... defaultValue)
    874    {
    875        return get(URI[].class, key, defaultValue);
    876    }
    877
    878    /**
    879     * Get a list of URIs associated with the given configuration key.
    880     * If the key doesn't map to an existing object an empty list is returned.
    881     *
    882     * @param key The configuration key.
    883     * @return The associated URI list if the key is found.
    884     *
    885     * @throws ConversionException is thrown if the key maps to an
    886     *         object that is not a list of URIs.
    887     */
    888    public List<URI> getURIList(final String key)
    889    {
    890        return getURIList(key, new ArrayList<URI>());
    891    }
    892
    893    /**
    894     * Get a list of URIs associated with the given configuration key.
    895     * If the key doesn't map to an existing object, the default value is
    896     * returned.
    897     *
    898     * @param key The configuration key.
    899     * @param defaultValue The default value.
    900     * @return The associated List of URIs.
    901     *
    902     * @throws ConversionException is thrown if the key maps to an
    903     *         object that is not a list of URIs.
    904     */
    905    public List<URI> getURIList(final String key, final List<URI> defaultValue)
    906    {
    907        return getList(URI.class, key, defaultValue);
    908    }
    909
    910    /**
    911     * Get an URL associated with the given configuration key.
    912     *
    913     * @param key The configuration key.
    914     * @return The associated URL.
    915     *
    916     * @throws ConversionException is thrown if the key maps to an
    917     *         object that is not an URL.
    918     */
    919    public URL getURL(final String key)
    920    {
    921        return get(URL.class, key);
    922    }
    923
    924    /**
    925     * Get an URL associated with the given configuration key.
    926     * If the key doesn't map to an existing object, the default value
    927     * is returned.
    928     *
    929     * @param key          The configuration key.
    930     * @param defaultValue The default value.
    931     * @return The associated URL.
    932     *
    933     * @throws ConversionException is thrown if the key maps to an
    934     *         object that is not an URL.
    935     */
    936    public URL getURL(final String key, final URL defaultValue)
    937    {
    938        return get(URL.class, key, defaultValue);
    939    }
    940
    941    /**
    942     * Get a list of URLs associated with the given configuration key.
    943     * If the key doesn't map to an existing object an empty list is returned.
    944     *
    945     * @param key The configuration key.
    946     * @return The associated URL list if the key is found.
    947     *
    948     * @throws ConversionException is thrown if the key maps to an
    949     *         object that is not a list of URLs.
    950     */
    951    public List<URL> getURLList(final String key)
    952    {
    953        return getURLList(key, new ArrayList<URL>());
    954    }
    955
    956    /**
    957     * Get a list of URLs associated with the given configuration key.
    958     * If the key doesn't map to an existing object, the default value is
    959     * returned.
    960     *
    961     * @param key The configuration key.
    962     * @param defaultValue The default value.
    963     * @return The associated List of URLs.
    964     *
    965     * @throws ConversionException is thrown if the key maps to an
    966     *         object that is not a list of URLs.
    967     */
    968    public List<URL> getURLList(final String key, final List<URL> defaultValue)
    969    {
    970        return getList(URL.class, key, defaultValue);
    971    }
    972
    973    /**
    974     * Get an array of URLs associated with the given configuration key.
    975     * If the key doesn't map to an existing object an empty array is returned.
    976     *
    977     * @param key The configuration key.
    978     * @return The associated URL array if the key is found.
    979     *
    980     * @throws ConversionException is thrown if the key maps to an
    981     *         object that is not a list of URLs.
    982     */
    983    public URL[] getURLArray(final String key)
    984    {
    985        return getURLArray(key, EMPTY_URL_ARRAY);
    986    }
    987
    988    /**
    989     * Get an array of URLs associated with the given configuration key.
    990     * If the key doesn't map to an existing object an empty array is returned.
    991     *
    992     * @param key The configuration key.
    993     * @param defaultValue the default value, which will be returned if the property is not found
    994     * @return The associated URL array if the key is found.
    995     *
    996     * @throws ConversionException is thrown if the key maps to an
    997     *         object that is not a list of URLs.
    998     */
    999    public URL[] getURLArray(final String key, final URL... defaultValue)
    1000    {
    1001        return get(URL[].class, key, defaultValue);
    1002    }
    1003
    1004    /**
    1005     * Get a Date associated with the given configuration key. If the property
    1006     * is a String, it will be parsed with the format defined by the user in
    1007     * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
    1008     * {@link #DEFAULT_DATE_FORMAT} pattern.
    1009     *
    1010     * @param key The configuration key.
    1011     * @return The associated Date.
    1012     *
    1013     * @throws ConversionException is thrown if the key maps to an
    1014     *         object that is not a Date.
    1015     */
    1016    public Date getDate(final String key)
    1017    {
    1018        return get(Date.class, key);
    1019    }
    1020
    1021    /**
    1022     * Get a Date associated with the given configuration key. If the property
    1023     * is a String, it will be parsed with the specified format pattern.
    1024     *
    1025     * @param key    The configuration key.
    1026     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1027     * @return The associated Date
    1028     *
    1029     * @throws ConversionException is thrown if the key maps to an
    1030     *         object that is not a Date.
    1031     */
    1032    public Date getDate(final String key, final String format)
    1033    {
    1034        final Date value = getDate(key, null, format);
    1035        if (value != null)
    1036        {
    1037            return value;
    1038        }
    1039        else if (isThrowExceptionOnMissing())
    1040        {
    1041            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
    1042        }
    1043        else
    1044        {
    1045            return null;
    1046        }
    1047    }
    1048
    1049    /**
    1050     * Get a Date associated with the given configuration key. If the property
    1051     * is a String, it will be parsed with the format defined by the user in
    1052     * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the
    1053     * {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map to an
    1054     * existing object, the default value is returned.
    1055     *
    1056     * @param key          The configuration key.
    1057     * @param defaultValue The default value.
    1058     * @return The associated Date.
    1059     *
    1060     * @throws ConversionException is thrown if the key maps to an
    1061     *         object that is not a Date.
    1062     */
    1063    public Date getDate(final String key, final Date defaultValue)
    1064    {
    1065        return getDate(key, defaultValue, null);
    1066    }
    1067
    1068    /**
    1069     * Get a Date associated with the given configuration key. If the property
    1070     * is a String, it will be parsed with the specified format pattern.
    1071     * If the key doesn't map to an existing object, the default value
    1072     * is returned.
    1073     *
    1074     * @param key          The configuration key.
    1075     * @param defaultValue The default value.
    1076     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1077     * @return The associated Date.
    1078     *
    1079     * @throws ConversionException is thrown if the key maps to an
    1080     *         object that is not a Date.
    1081     */
    1082    public Date getDate(final String key, final Date defaultValue, final String format)
    1083    {
    1084        TEMP_DATE_FORMAT.set(format);
    1085        try
    1086        {
    1087            return get(Date.class, key, defaultValue);
    1088        }
    1089        finally
    1090        {
    1091            TEMP_DATE_FORMAT.remove();
    1092        }
    1093    }
    1094
    1095    public List<Date> getDateList(final String key)
    1096    {
    1097        return getDateList(key, new ArrayList<Date>());
    1098    }
    1099
    1100    /**
    1101     * Get a list of Dates associated with the given configuration key.
    1102     * If the property is a list of Strings, they will be parsed with the
    1103     * specified format pattern. If the key doesn't map to an existing object
    1104     * an empty list is returned.
    1105     *
    1106     * @param key    The configuration key.
    1107     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1108     * @return The associated Date list if the key is found.
    1109     *
    1110     * @throws ConversionException is thrown if the key maps to an
    1111     *         object that is not a list of Dates.
    1112     */
    1113    public List<Date> getDateList(final String key, final String format)
    1114    {
    1115        return getDateList(key, new ArrayList<Date>(), format);
    1116    }
    1117
    1118    /**
    1119     * Get a list of Dates associated with the given configuration key.
    1120     * If the property is a list of Strings, they will be parsed with the
    1121     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1122     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1123     * If the key doesn't map to an existing object, the default value is
    1124     * returned.
    1125     *
    1126     * @param key          The configuration key.
    1127     * @param defaultValue The default value.
    1128     * @return The associated Date list if the key is found.
    1129     *
    1130     * @throws ConversionException is thrown if the key maps to an
    1131     *         object that is not a list of Dates.
    1132     */
    1133    public List<Date> getDateList(final String key, final List<Date> defaultValue)
    1134    {
    1135        return getDateList(key, defaultValue, null);
    1136    }
    1137
    1138    /**
    1139     * Get a list of Dates associated with the given configuration key.
    1140     * If the property is a list of Strings, they will be parsed with the
    1141     * specified format pattern. If the key doesn't map to an existing object,
    1142     * the default value is returned.
    1143     *
    1144     * @param key          The configuration key.
    1145     * @param defaultValue The default value.
    1146     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1147     * @return The associated Date list if the key is found.
    1148     *
    1149     * @throws ConversionException is thrown if the key maps to an
    1150     *         object that is not a list of Dates.
    1151     */
    1152    public List<Date> getDateList(final String key, final List<Date> defaultValue, final String format)
    1153    {
    1154        TEMP_DATE_FORMAT.set(format);
    1155        try
    1156        {
    1157            return getList(Date.class, key, defaultValue);
    1158        }
    1159        finally
    1160        {
    1161            TEMP_DATE_FORMAT.remove();
    1162        }
    1163    }
    1164
    1165    /**
    1166     * Get an array of Dates associated with the given configuration key.
    1167     * If the property is a list of Strings, they will be parsed with the
    1168     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1169     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1170     * If the key doesn't map to an existing object an empty array is returned.
    1171     *
    1172     * @param key The configuration key.
    1173     * @return The associated Date array if the key is found.
    1174     *
    1175     * @throws ConversionException is thrown if the key maps to an
    1176     *         object that is not a list of Dates.
    1177     */
    1178    public Date[] getDateArray(final String key)
    1179    {
    1180        return getDateArray(key, EMPTY_DATE_ARRAY);
    1181    }
    1182
    1183    /**
    1184     * Get an array of Dates associated with the given configuration key.
    1185     * If the property is a list of Strings, they will be parsed with the
    1186     * specified format pattern. If the key doesn't map to an existing object
    1187     * an empty array is returned.
    1188     *
    1189     * @param key    The configuration key.
    1190     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1191     * @return The associated Date array if the key is found.
    1192     *
    1193     * @throws ConversionException is thrown if the key maps to an
    1194     *         object that is not a list of Dates.
    1195     */
    1196    public Date[] getDateArray(final String key, final String format)
    1197    {
    1198        return getDateArray(key, EMPTY_DATE_ARRAY, format);
    1199    }
    1200
    1201    /**
    1202     * Get an array of Dates associated with the given configuration key.
    1203     * If the property is a list of Strings, they will be parsed with the
    1204     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1205     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1206     * If the key doesn't map to an existing object an empty array is returned.
    1207     *
    1208     * @param key The configuration key.
    1209     * @param defaultValue the default value, which will be returned if the property is not found
    1210     * @return The associated Date array if the key is found.
    1211     *
    1212     * @throws ConversionException is thrown if the key maps to an
    1213     *         object that is not a list of Dates.
    1214     */
    1215    public Date[] getDateArray(final String key, final Date... defaultValue)
    1216    {
    1217        return getDateArray(key, defaultValue, null);
    1218    }
    1219
    1220    /**
    1221     * Get an array of Dates associated with the given configuration key.
    1222     * If the property is a list of Strings, they will be parsed with the
    1223     * specified format pattern. If the key doesn't map to an existing object,
    1224     * the default value is returned.
    1225     *
    1226     * @param key          The configuration key.
    1227     * @param defaultValue The default value.
    1228     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1229     * @return The associated Date array if the key is found.
    1230     *
    1231     * @throws ConversionException is thrown if the key maps to an
    1232     *         object that is not a list of Dates.
    1233     */
    1234    public Date[] getDateArray(final String key, final Date[] defaultValue, final String format)
    1235    {
    1236        TEMP_DATE_FORMAT.set(format);
    1237        try
    1238        {
    1239            return get(Date[].class, key, defaultValue);
    1240        }
    1241        finally
    1242        {
    1243            TEMP_DATE_FORMAT.remove();
    1244        }
    1245    }
    1246
    1247    /**
    1248     * Get a Calendar associated with the given configuration key. If the
    1249     * property is a String, it will be parsed with the format defined by the
    1250     * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
    1251     * with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1252     *
    1253     * @param key The configuration key.
    1254     * @return The associated Calendar.
    1255     *
    1256     * @throws ConversionException is thrown if the key maps to an
    1257     *         object that is not a Calendar.
    1258     */
    1259    public Calendar getCalendar(final String key)
    1260    {
    1261        return get(Calendar.class, key);
    1262    }
    1263
    1264    /**
    1265     * Get a Calendar associated with the given configuration key. If the
    1266     * property is a String, it will be parsed with the specified format
    1267     * pattern.
    1268     *
    1269     * @param key    The configuration key.
    1270     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1271     * @return The associated Calendar
    1272     *
    1273     * @throws ConversionException is thrown if the key maps to an
    1274     *         object that is not a Calendar.
    1275     */
    1276    public Calendar getCalendar(final String key, final String format)
    1277    {
    1278        final Calendar value = getCalendar(key, null, format);
    1279        if (value != null)
    1280        {
    1281            return value;
    1282        }
    1283        else if (isThrowExceptionOnMissing())
    1284        {
    1285            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
    1286        }
    1287        else
    1288        {
    1289            return null;
    1290        }
    1291    }
    1292
    1293    /**
    1294     * Get a Calendar associated with the given configuration key. If the
    1295     * property is a String, it will be parsed with the format defined by the
    1296     * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined
    1297     * with the {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map
    1298     * to an existing object, the default value is returned.
    1299     *
    1300     * @param key          The configuration key.
    1301     * @param defaultValue The default value.
    1302     * @return The associated Calendar.
    1303     *
    1304     * @throws ConversionException is thrown if the key maps to an
    1305     *         object that is not a Calendar.
    1306     */
    1307    public Calendar getCalendar(final String key, final Calendar defaultValue)
    1308    {
    1309        return getCalendar(key, defaultValue, null);
    1310    }
    1311
    1312    /**
    1313     * Get a Calendar associated with the given configuration key. If the
    1314     * property is a String, it will be parsed with the specified format
    1315     * pattern. If the key doesn't map to an existing object, the default
    1316     * value is returned.
    1317     *
    1318     * @param key          The configuration key.
    1319     * @param defaultValue The default value.
    1320     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1321     * @return The associated Calendar.
    1322     *
    1323     * @throws ConversionException is thrown if the key maps to an
    1324     *         object that is not a Calendar.
    1325     */
    1326    public Calendar getCalendar(final String key, final Calendar defaultValue, final String format)
    1327    {
    1328        TEMP_DATE_FORMAT.set(format);
    1329        try
    1330        {
    1331            return get(Calendar.class, key, defaultValue);
    1332        }
    1333        finally
    1334        {
    1335            TEMP_DATE_FORMAT.remove();
    1336        }
    1337    }
    1338
    1339    /**
    1340     * Get a list of Calendars associated with the given configuration key.
    1341     * If the property is a list of Strings, they will be parsed with the
    1342     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1343     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1344     * If the key doesn't map to an existing object an empty list is returned.
    1345     *
    1346     * @param key The configuration key.
    1347     * @return The associated Calendar list if the key is found.
    1348     *
    1349     * @throws ConversionException is thrown if the key maps to an
    1350     *         object that is not a list of Calendars.
    1351     */
    1352    public List<Calendar> getCalendarList(final String key)
    1353    {
    1354        return getCalendarList(key, new ArrayList<Calendar>());
    1355    }
    1356
    1357    /**
    1358     * Get a list of Calendars associated with the given configuration key.
    1359     * If the property is a list of Strings, they will be parsed with the
    1360     * specified format pattern. If the key doesn't map to an existing object
    1361     * an empty list is returned.
    1362     *
    1363     * @param key    The configuration key.
    1364     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1365     * @return The associated Calendar list if the key is found.
    1366     *
    1367     * @throws ConversionException is thrown if the key maps to an
    1368     *         object that is not a list of Calendars.
    1369     */
    1370    public List<Calendar> getCalendarList(final String key, final String format)
    1371    {
    1372        return getCalendarList(key, new ArrayList<Calendar>(), format);
    1373    }
    1374
    1375    /**
    1376     * Get a list of Calendars associated with the given configuration key.
    1377     * If the property is a list of Strings, they will be parsed with the
    1378     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1379     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1380     * If the key doesn't map to an existing object, the default value is
    1381     * returned.
    1382     *
    1383     * @param key The configuration key.
    1384     * @param defaultValue The default value.
    1385     * @return The associated Calendar list if the key is found.
    1386     *
    1387     * @throws ConversionException is thrown if the key maps to an
    1388     *         object that is not a list of Calendars.
    1389     */
    1390    public List<Calendar> getCalendarList(final String key, final List<Calendar> defaultValue)
    1391    {
    1392        return getCalendarList(key, defaultValue, null);
    1393    }
    1394
    1395    /**
    1396     * Get a list of Calendars associated with the given configuration key.
    1397     * If the property is a list of Strings, they will be parsed with the
    1398     * specified format pattern. If the key doesn't map to an existing object,
    1399     * the default value is returned.
    1400     *
    1401     * @param key          The configuration key.
    1402     * @param defaultValue The default value.
    1403     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1404     * @return The associated Calendar list if the key is found.
    1405     *
    1406     * @throws ConversionException is thrown if the key maps to an
    1407     *         object that is not a list of Calendars.
    1408     */
    1409    public List<Calendar> getCalendarList(final String key, final List<Calendar> defaultValue, final String format)
    1410    {
    1411        TEMP_DATE_FORMAT.set(format);
    1412        try
    1413        {
    1414            return getList(Calendar.class, key, defaultValue);
    1415        }
    1416        finally
    1417        {
    1418            TEMP_DATE_FORMAT.remove();
    1419        }
    1420    }
    1421
    1422    /**
    1423     * Get an array of Calendars associated with the given configuration key.
    1424     * If the property is a list of Strings, they will be parsed with the
    1425     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1426     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1427     * If the key doesn't map to an existing object an empty array is returned.
    1428     *
    1429     * @param key The configuration key.
    1430     * @return The associated Calendar array if the key is found.
    1431     *
    1432     * @throws ConversionException is thrown if the key maps to an
    1433     *         object that is not a list of Calendars.
    1434     */
    1435    public Calendar[] getCalendarArray(final String key)
    1436    {
    1437        return getCalendarArray(key, EMPTY_CALENDARD_ARRAY);
    1438    }
    1439
    1440    /**
    1441     * Get an array of Calendars associated with the given configuration key.
    1442     * If the property is a list of Strings, they will be parsed with the
    1443     * specified format pattern. If the key doesn't map to an existing object
    1444     * an empty array is returned.
    1445     *
    1446     * @param key    The configuration key.
    1447     * @param format The non-localized {@link java.text.DateFormat} pattern.
    1448     * @return The associated Calendar array if the key is found.
    1449     *
    1450     * @throws ConversionException is thrown if the key maps to an
    1451     *         object that is not a list of Calendars.
    1452     */
    1453    public Calendar[] getCalendarArray(final String key, final String format)
    1454    {
    1455        return getCalendarArray(key, EMPTY_CALENDARD_ARRAY, format);
    1456    }
    1457
    1458    /**
    1459     * Get an array of Calendars associated with the given configuration key.
    1460     * If the property is a list of Strings, they will be parsed with the
    1461     * format defined by the user in the {@link #DATE_FORMAT_KEY} property,
    1462     * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern.
    1463     * If the key doesn't map to an existing object an empty array is returned.
    1464     *
    1465     * @param key The configuration key.
    1466     * @param defaultValue the default value, which will be returned if the property is not found
    1467     * @return The associated Calendar array if the key is found.
    1468     *
    1469     * @throws ConversionException is thrown if the key maps to an
    1470     *         object that is not a list of Calendars.
    1471     */
    1472    public Calendar[] getCalendarArray(final String key, final Calendar... defaultValue)
    1473    {
    1474        return getCalendarArray(key, defaultValue, null);
    1475    }
    1476
    1477    /**
    1478     * Get an array of Calendars associated with the given configuration key.
    1479     * If the property is a list of Strings, they will be parsed with the
    1480     * specified format pattern. If the key doesn't map to an existing object,
    1481     * the default value is returned.
    1482     *
    1483     * @param key          The configuration key.
    1484     * @param defaultValue The default value.
    1485     * @param format       The non-localized {@link java.text.DateFormat} pattern.
    1486     * @return The associated Calendar array if the key is found.
    1487     *
    1488     * @throws ConversionException is thrown if the key maps to an
    1489     *         object that is not a list of Calendars.
    1490     */
    1491    public Calendar[] getCalendarArray(final String key, final Calendar[] defaultValue, final String format)
    1492    {
    1493        TEMP_DATE_FORMAT.set(format);
    1494        try
    1495        {
    1496            return get(Calendar[].class, key, defaultValue);
    1497        }
    1498        finally
    1499        {
    1500            TEMP_DATE_FORMAT.remove();
    1501        }
    1502    }
    1503
    1504    /**
    1505     * Returns the date format specified by the user in the DATE_FORMAT_KEY
    1506     * property, or the default format otherwise.
    1507     *
    1508     * @return the default date format
    1509     */
    1510    private String getDefaultDateFormat()
    1511    {
    1512        return getString(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT);
    1513    }
    1514
    1515    /**
    1516     * Get a Locale associated with the given configuration key.
    1517     *
    1518     * @param key The configuration key.
    1519     * @return The associated Locale.
    1520     *
    1521     * @throws ConversionException is thrown if the key maps to an
    1522     *         object that is not a Locale.
    1523     */
    1524    public Locale getLocale(final String key)
    1525    {
    1526        return get(Locale.class, key);
    1527    }
    1528
    1529    /**
    1530     * Get a Locale associated with the given configuration key.
    1531     * If the key doesn't map to an existing object, the default value
    1532     * is returned.
    1533     *
    1534     * @param key          The configuration key.
    1535     * @param defaultValue The default value.
    1536     * @return The associated Locale.
    1537     *
    1538     * @throws ConversionException is thrown if the key maps to an
    1539     *         object that is not a Locale.
    1540     */
    1541    public Locale getLocale(final String key, final Locale defaultValue)
    1542    {
    1543        return get(Locale.class, key, defaultValue);
    1544    }
    1545
    1546    /**
    1547     * Get a list of Locales associated with the given configuration key.
    1548     * If the key doesn't map to an existing object an empty list is returned.
    1549     *
    1550     * @param key The configuration key.
    1551     * @return The associated Locale list if the key is found.
    1552     *
    1553     * @throws ConversionException is thrown if the key maps to an
    1554     *         object that is not a list of Locales.
    1555     */
    1556    public List<Locale> getLocaleList(final String key)
    1557    {
    1558        return getLocaleList(key, new ArrayList<Locale>());
    1559    }
    1560
    1561    /**
    1562     * Get a list of Locales associated with the given configuration key.
    1563     * If the key doesn't map to an existing object, the default value is
    1564     * returned.
    1565     *
    1566     * @param key The configuration key.
    1567     * @param defaultValue The default value.
    1568     * @return The associated List of Locales.
    1569     *
    1570     * @throws ConversionException is thrown if the key maps to an
    1571     *         object that is not a list of Locales.
    1572     */
    1573    public List<Locale> getLocaleList(final String key, final List<Locale> defaultValue)
    1574    {
    1575        return getList(Locale.class, key, defaultValue);
    1576    }
    1577
    1578    /**
    1579     * Get an array of Locales associated with the given
    1580     * configuration key. If the key doesn't map to an existing object
    1581     * an empty array is returned.
    1582     *
    1583     * @param key The configuration key.
    1584     * @return The associated Locale array if the key is found.
    1585     *
    1586     * @throws ConversionException is thrown if the key maps to an
    1587     *         object that is not a list of Locales.
    1588     */
    1589    public Locale[] getLocaleArray(final String key)
    1590    {
    1591        return getLocaleArray(key, EMPTY_LOCALE_ARRAY);
    1592    }
    1593
    1594    /**
    1595     * Get an array of Locales associated with the given
    1596     * configuration key. If the key doesn't map to an existing object
    1597     * an empty array is returned.
    1598     *
    1599     * @param key The configuration key.
    1600     * @param defaultValue the default value, which will be returned if the property is not found
    1601     * @return The associated Locale array if the key is found.
    1602     *
    1603     * @throws ConversionException is thrown if the key maps to an
    1604     *         object that is not a list of Locales.
    1605     */
    1606    public Locale[] getLocaleArray(final String key, final Locale... defaultValue)
    1607    {
    1608        return get(Locale[].class, key, defaultValue);
    1609    }
    1610
    1611    /**
    1612     * Get a Color associated with the given configuration key.
    1613     *
    1614     * @param key The configuration key.
    1615     * @return The associated Color.
    1616     *
    1617     * @throws ConversionException is thrown if the key maps to an
    1618     *         object that is not a Color.
    1619     */
    1620    public Color getColor(final String key)
    1621    {
    1622        return get(Color.class, key);
    1623    }
    1624
    1625    /**
    1626     * Get a Color associated with the given configuration key.
    1627     * If the key doesn't map to an existing object, the default value
    1628     * is returned.
    1629     *
    1630     * @param key          The configuration key.
    1631     * @param defaultValue The default value.
    1632     * @return The associated Color.
    1633     *
    1634     * @throws ConversionException is thrown if the key maps to an
    1635     *         object that is not a Color.
    1636     */
    1637    public Color getColor(final String key, final Color defaultValue)
    1638    {
    1639        return get(Color.class, key, defaultValue);
    1640    }
    1641
    1642    /**
    1643     * Get a list of Colors associated with the given configuration key.
    1644     * If the key doesn't map to an existing object an empty list is returned.
    1645     *
    1646     * @param key The configuration key.
    1647     * @return The associated Color list if the key is found.
    1648     *
    1649     * @throws ConversionException is thrown if the key maps to an
    1650     *         object that is not a list of Colors.
    1651     */
    1652    public List<Color> getColorList(final String key)
    1653    {
    1654        return getColorList(key, new ArrayList<Color>());
    1655    }
    1656
    1657    /**
    1658     * Get a list of Colors associated with the given configuration key.
    1659     * If the key doesn't map to an existing object, the default value is
    1660     * returned.
    1661     *
    1662     * @param key The configuration key.
    1663     * @param defaultValue The default value.
    1664     * @return The associated List of Colors.
    1665     *
    1666     * @throws ConversionException is thrown if the key maps to an
    1667     *         object that is not a list of Colors.
    1668     */
    1669    public List<Color> getColorList(final String key, final List<Color> defaultValue)
    1670    {
    1671        return getList(Color.class, key, defaultValue);
    1672    }
    1673
    1674    /**
    1675     * Get an array of Colors associated with the given
    1676     * configuration key. If the key doesn't map to an existing object
    1677     * an empty array is returned.
    1678     *
    1679     * @param key The configuration key.
    1680     * @return The associated Color array if the key is found.
    1681     *
    1682     * @throws ConversionException is thrown if the key maps to an
    1683     *         object that is not a list of Colors.
    1684     */
    1685    public Color[] getColorArray(final String key)
    1686    {
    1687        return getColorArray(key, EMPTY_COLOR_ARRAY);
    1688    }
    1689
    1690    /**
    1691     * Get an array of Colors associated with the given
    1692     * configuration key. If the key doesn't map to an existing object
    1693     * an empty array is returned.
    1694     *
    1695     * @param key The configuration key.
    1696     * @param defaultValue the default value, which will be returned if the property is not found
    1697     * @return The associated Color array if the key is found.
    1698     *
    1699     * @throws ConversionException is thrown if the key maps to an
    1700     *         object that is not a list of Colors.
    1701     */
    1702    public Color[] getColorArray(final String key, final Color... defaultValue)
    1703    {
    1704        return get(Color[].class, key, defaultValue);
    1705    }
    1706
    1707    /**
    1708     * Returns the original conversion handler set for this configuration. If
    1709     * this is not a {@code DefaultConversionHandler}, result is <b>null</b>.
    1710     *
    1711     * @return the original conversion handler or <b>null</b>
    1712     */
    1713    private DefaultConversionHandler getOriginalConversionHandler()
    1714    {
    1715        final ConversionHandler handler = super.getConversionHandler();
    1716        return (DefaultConversionHandler) (handler instanceof DefaultConversionHandler ? handler
    1717                : null);
    1718    }
    1719
    1720    /**
    1721     * A specialized {@code ConversionHandler} implementation which allows
    1722     * overriding the date format pattern. This class takes care that the format
    1723     * pattern can be defined as a property of the wrapped configuration or
    1724     * temporarily passed when calling a conversion method.
    1725     */
    1726    private class DataConversionHandler extends DefaultConversionHandler
    1727    {
    1728        /**
    1729         * {@inheritDoc} This implementation checks for a defined data format in
    1730         * the following order:
    1731         * <ul>
    1732         * <li>If a temporary date format is set for the current call, it is
    1733         * used.</li>
    1734         * <li>If a date format is specified in this configuration using the
    1735         * {@code DATE_FORMAT_KEY} property, it is used.</li>
    1736         * <li>Otherwise, the date format set for the original conversion
    1737         * handler is used if available.</li>
    1738         * </ul>
    1739         */
    1740        @Override
    1741        public String getDateFormat()
    1742        {
    1743            if (StringUtils.isNotEmpty(TEMP_DATE_FORMAT.get()))
    1744            {
    1745                return TEMP_DATE_FORMAT.get();
    1746            }
    1747            if (containsKey(DATE_FORMAT_KEY))
    1748            {
    1749                return getDefaultDateFormat();
    1750            }
    1751
    1752            final DefaultConversionHandler orgHandler =
    1753                    getOriginalConversionHandler();
    1754            return orgHandler != null ? orgHandler.getDateFormat() : null;
    1755        }
    1756    }
    1757}