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