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