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