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