You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by eb...@apache.org on 2007/04/18 01:46:35 UTC

svn commit: r529806 - in /jakarta/commons/proper/configuration/trunk: src/java/org/apache/commons/configuration/ src/test/org/apache/commons/configuration/ xdocs/

Author: ebourg
Date: Tue Apr 17 16:46:34 2007
New Revision: 529806

URL: http://svn.apache.org/viewvc?view=rev&rev=529806
Log:
Added generic getters to DataConfiguration and factorized the code
The getters without default value in DataConfiguration now throw an exception on missing properties if the flag is set
Improved the javadoc on DataConfiguration

Modified:
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DataConfiguration.java
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java
    jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDataConfiguration.java
    jakarta/commons/proper/configuration/trunk/xdocs/changes.xml

Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DataConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DataConfiguration.java?view=diff&rev=529806&r1=529805&r2=529806
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DataConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DataConfiguration.java Tue Apr 17 16:46:34 2007
@@ -18,6 +18,8 @@
 package org.apache.commons.configuration;
 
 import java.awt.Color;
+import java.io.Serializable;
+import java.lang.reflect.Array;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.net.URL;
@@ -28,10 +30,9 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.io.Serializable;
+import java.util.NoSuchElementException;
 
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.ClassUtils;
 import org.apache.commons.lang.StringUtils;
 
 /**
@@ -39,9 +40,32 @@
  * Configuration supports more types: URL, Locale, Date, Calendar, Color, as
  * well as lists and arrays for all types.
  *
- * <p>Let us know if you find this useful, the most frequently used getters
- * are likely to be integrated in the Configuration interface in a future
- * version.</p>
+ * <h4>Example</h4>
+ *
+ * Configuration file <tt>config.properties</tt>:
+ * <pre>
+ * title.color = #0000FF
+ * default.locales = fr,en,de
+ * </pre>
+ *
+ * Usage:
+ *
+ * <pre>
+ * DataConfiguration config = new DataConfiguration(new PropertiesConfiguration("config.properties"));
+ *
+ * // retrieve a property using a specialized getter
+ * Color color = config.getColor("title.color");
+ *
+ * // retrieve a property using a generic getter
+ * Locale[] locales = (Locale[]) config.getArray(Locale.class, "default.locales");
+ * </pre>
+ *
+ * <h4>Dates</h4>
+ *
+ * Date objects are expected to be formatted with the pattern <tt>yyyy-MM-dd HH:mm:ss</tt>.
+ * This default format can be changed by specifying another format in the
+ * getters, or by putting a date format in the configuration under the key
+ * <tt>org.apache.commons.configuration.format.date</tt>.
  *
  * @author <a href="ebourg@apache.org">Emmanuel Bourg</a>
  * @version $Revision$, $Date$
@@ -122,225 +146,182 @@
     }
 
     /**
-     * Get a list of Boolean objects associated with the given
-     * configuration key. If the key doesn't map to an existing object
-     * an empty list is returned.
+     * Get an object of the specified type associated with the given
+     * configuration key. If the key doesn't map to an existing object, the
+     * method returns null unless {@link #isThrowExceptionOnMissing()} is set
+     * to <tt>true</tt>.
      *
-     * @param key The configuration key.
-     * @return The associated Boolean list if the key is found.
+     * @param cls the target type of the value
+     * @param key the key of the value
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of booleans.
-     */
-    public List getBooleanList(String key)
-    {
-        return getBooleanList(key, new ArrayList());
-    }
-
-    /**
-     * Get a list of Boolean objects associated with the given
-     * configuration key. If the key doesn't map to an existing object,
-     * the default value is returned.
+     * @return the value of the requested type for the key
      *
-     * @param key The configuration key.
-     * @param defaultValue The default value.
-     * @return The associated List of strings.
+     * @throws NoSuchElementException if the key doesn't map to an existing
+     *     object and <tt>throwExceptionOnMissing=true</tt>
+     * @throws ConversionException if the value is not compatible with the requested type
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of booleans.
+     * @since 1.5
      */
-    public List getBooleanList(String key, List defaultValue)
+    public Object get(Class cls, String key)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof boolean[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((boolean[]) value));
-        }
-        else if (value instanceof Boolean[])
+        Object value = get(cls, key, null);
+        if (value != null)
         {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Boolean[]) value);
+            return value;
         }
-        else if (value instanceof Collection)
+        else if (isThrowExceptionOnMissing())
         {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toBoolean(interpolate(it.next())));
-            }
+            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
         }
         else
         {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toBoolean(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of booleans", e);
-            }
+            return null;
         }
-
-        return list;
     }
 
     /**
-     * Get an array of boolean primitives associated with the given
-     * configuration key. If the key doesn't map to an existing object
-     * an empty array is returned.
+     * Get an object of the specified type associated with the given
+     * configuration key. If the key doesn't map to an existing object, the
+     * default value is returned.
      *
-     * @param key The configuration key.
-     * @return The associated boolean array if the key is found.
+     * @param cls          the target type of the value
+     * @param key          the key of the value
+     * @param defaultValue the default value
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of booleans.
-     */
-    public boolean[] getBooleanArray(String key)
-    {
-        return getBooleanArray(key, new boolean[0]);
-    }
-
-    /**
-     * Get an array of boolean primitives associated with the given
-     * configuration key. If the key doesn't map to an existing object,
-     * the default value is returned.
+     * @return the value of the requested type for the key
      *
-     * @param key          The configuration key.
-     * @param defaultValue The default value.
-     * @return The associated boolean array if the key is found.
+     * @throws ConversionException if the value is not compatible with the requested type
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of booleans.
+     * @since 1.5
      */
-    public boolean[] getBooleanArray(String key, boolean[] defaultValue)
+    public Object get(Class cls, String key, Object defaultValue)
     {
-        Object value = getProperty(key);
-
-        boolean[] array;
+        Object value = resolveContainerStore(key);
 
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof boolean[])
-        {
-            array = (boolean[]) value;
-        }
-        else if (value instanceof Boolean[])
-        {
-            array = ArrayUtils.toPrimitive((Boolean[]) value);
-        }
-        else if (value instanceof Collection)
+        if (value == null)
         {
-            Collection values = (Collection) value;
-            array = new boolean[values.size()];
-
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toBoolean(interpolate(it.next())).booleanValue();
-            }
+            return defaultValue;
         }
         else
         {
             try
             {
-                // attempt to convert a single value
-                array = new boolean[1];
-                array[0] = PropertyConverter.toBoolean(interpolate(value)).booleanValue();
+                if (Date.class.equals(cls) || Calendar.class.equals(cls))
+                {
+                    return PropertyConverter.to(cls, interpolate(value), new String[] { getDefaultDateFormat() });
+                }
+                else
+                {
+                    return PropertyConverter.to(cls, interpolate(value), null);
+                }
             }
             catch (ConversionException e)
             {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of booleans", e);
+                throw new ConversionException('\'' + key + "' doesn't map to a " + cls, e);
             }
         }
-
-        return array;
     }
 
     /**
-     * Get a list of Byte objects associated with the given configuration key.
-     * If the key doesn't map to an existing object an empty list is returned.
+     * Get a list of typed objects associated with the given configuration key.
+     * If the key doesn't map to an existing object, an empty list is returned.
      *
+     * @param cls the type expected for the elements of the list
      * @param key The configuration key.
-     * @return The associated Byte list if the key is found.
+     * @return The associated list if the key is found.
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of bytes.
+     * @throws ConversionException is thrown if the key maps to an object that
+     *     is not compatible with a list of the specified class.
+     *
+     * @since 1.5
      */
-    public List getByteList(String key)
+    public List getList(Class cls, String key)
     {
-        return getByteList(key, new ArrayList());
+        return getList(cls, key, new ArrayList());
     }
 
     /**
-     * Get a list of Byte objects associated with the given configuration key.
+     * Get a list of typed objects associated with the given configuration key.
      * If the key doesn't map to an existing object, the default value is
      * returned.
      *
-     * @param key The configuration key.
-     * @param defaultValue The default value.
-     * @return The associated List of Bytes.
+     * @param cls the      type expected for the elements of the list
+     * @param key          the configuration key.
+     * @param defaultValue the default value.
+     * @return The associated List.
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of bytes.
+     * @throws ConversionException is thrown if the key maps to an object that
+     *     is not compatible with a list of the specified class.
+     *
+     * @since 1.5
      */
-    public List getByteList(String key, List defaultValue)
+    public List getList(Class cls, String key, List defaultValue)
     {
         Object value = getProperty(key);
+        Class valueClass = value != null ? value.getClass() : null;
 
         List list;
 
         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
         {
+            // the value is null or is an empty string
             list = defaultValue;
         }
-        else if (value instanceof byte[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((byte[]) value));
-        }
-        else if (value instanceof Byte[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Byte[]) value);
-        }
-        else if (value instanceof Collection)
+        else
         {
-            Collection values = (Collection) value;
             list = new ArrayList();
 
-            Iterator it = values.iterator();
-            while (it.hasNext())
+            Object[] params = null;
+            if (cls.equals(Date.class) || cls.equals(Calendar.class))
             {
-                list.add(PropertyConverter.toByte(interpolate(it.next())));
+                params = new Object[] { getDefaultDateFormat() };
             }
-        }
-        else
-        {
+
             try
             {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toByte(interpolate(value)));
+                if (valueClass.isArray())
+                {
+                    // get the class of the objects contained in the array
+                    Class arrayType = valueClass.getComponentType();
+                    int length = Array.getLength(value);
+
+                    if (arrayType.equals(cls) || (arrayType.isPrimitive() && cls.equals(ClassUtils.primitiveToWrapper(arrayType))))
+                    {
+                        // the value is an array of the specified type, or an array
+                        // of the primitive type derived from the specified type
+                        for (int i = 0; i < length; i++)
+                        {
+                            list.add(Array.get(value, i));
+                        }
+                    }
+                    else
+                    {
+                        // attempt to convert the elements of the array
+                        for (int i = 0; i < length; i++)
+                        {
+                            list.add(PropertyConverter.to(cls, interpolate(Array.get(value, i)), params));
+                        }
+                    }
+                }
+                else if (value instanceof Collection)
+                {
+                    Collection values = (Collection) value;
+
+                    Iterator it = values.iterator();
+                    while (it.hasNext())
+                    {
+                        list.add(PropertyConverter.to(cls, interpolate(it.next()), params));
+                    }
+                }
+                else
+                {
+                    // attempt to convert a single value
+                    list.add(PropertyConverter.to(cls, interpolate(value), params));
+                }
             }
             catch (ConversionException e)
             {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of bytes", e);
+                throw new ConversionException("'" + key + "' doesn't map to a list of " + cls, e);
             }
         }
 
@@ -348,228 +329,344 @@
     }
 
     /**
-     * Get an array of byte primitives associated with the given
-     * configuration key. If the key doesn't map to an existing object
-     * an empty array is returned.
+     * Get an array of typed objects associated with the given configuration key.
+     * If the key doesn't map to an existing object, an empty list is returned.
      *
+     * @param cls the type expected for the elements of the array
      * @param key The configuration key.
-     * @return The associated byte array if the key is found.
+     * @return The associated array if the key is found, and the value compatible with the type specified.
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of bytes.
+     * @throws ConversionException is thrown if the key maps to an object that
+     *     is not compatible with a list of the specified class.
+     *
+     * @since 1.5
      */
-    public byte[] getByteArray(String key)
+    public Object getArray(Class cls, String key)
     {
-        return getByteArray(key, new byte[0]);
+        return getArray(cls, key, Array.newInstance(cls, 0));
     }
 
     /**
-     * Get an array of byte primitives associated with the given
-     * configuration key. If the key doesn't map to an existing object
-     * an empty array is returned.
+     * Get an array of typed objects associated with the given configuration key.
+     * If the key doesn't map to an existing object, the default value is returned.
      *
-     * @param key The configuration key.
-     * @param defaultValue the default value, which will be returned if the property is not found
-     * @return The associated byte array if the key is found.
+     * @param cls          the type expected for the elements of the array
+     * @param key          the configuration key.
+     * @param defaultValue the default value
+     * @return The associated array if the key is found, and the value compatible with the type specified.
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of bytes.
+     * @throws ConversionException is thrown if the key maps to an object that
+     *     is not compatible with an array of the specified class.
+     * @throws IllegalArgumentException if the default value is not an array of the specified type
+     *
+     * @since 1.5
      */
-    public byte[] getByteArray(String key, byte[] defaultValue)
+    public Object getArray(Class cls, String key, Object defaultValue)
     {
-        Object value = getProperty(key);
-
-        byte[] array;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof byte[])
+        // check the type of the default value
+        if (defaultValue != null && (!defaultValue.getClass().isArray() || !cls.isAssignableFrom(defaultValue.getClass().getComponentType())))
         {
-            array = (byte[]) value;
+            throw new IllegalArgumentException("The type of the default value (" + defaultValue.getClass() + ") is not an array of the specified class (" + cls + ")");
         }
-        else if (value instanceof Byte[])
+
+        if (cls.isPrimitive())
         {
-            array = ArrayUtils.toPrimitive((Byte[]) value);
+            return getPrimitiveArray(cls, key, defaultValue);
         }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            array = new byte[values.size()];
 
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toByte(interpolate(it.next())).byteValue();
-            }
+        List list = getList(cls, key);
+        if (list.isEmpty())
+        {
+            return defaultValue;
         }
         else
         {
-            try
-            {
-                // attempt to convert a single value
-                array = new byte[1];
-                array[0] = PropertyConverter.toByte(interpolate(value)).byteValue();
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of bytes", e);
-            }
+            return list.toArray((Object[]) Array.newInstance(cls, list.size()));
         }
-
-        return array;
     }
 
     /**
-     * Get a list of Short objects associated with the given configuration key.
-     * If the key doesn't map to an existing object an empty list is returned.
-     *
-     * @param key The configuration key.
-     * @return The associated Short list if the key is found.
+     * Get an array of primitive values associated with the given configuration key.
+     * If the key doesn't map to an existing object, the default value is returned.
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of shorts.
-     */
-    public List getShortList(String key)
-    {
-        return getShortList(key, new ArrayList());
-    }
-
-    /**
-     * Get a list of Short objects associated with the given configuration key.
-     * If the key doesn't map to an existing object, the default value is
-     * returned.
+     * @param cls          the primitive type expected for the elements of the array
+     * @param key          the configuration key.
+     * @param defaultValue the default value
+     * @return The associated array if the key is found, and the value compatible with the type specified.
      *
-     * @param key The configuration key.
-     * @param defaultValue The default value.
-     * @return The associated List of Shorts.
+     * @throws ConversionException is thrown if the key maps to an object that
+     *     is not compatible with an array of the specified class.
      *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of shorts.
+     * @since 1.5
      */
-    public List getShortList(String key, List defaultValue)
+    private Object getPrimitiveArray(Class cls, String key, Object defaultValue)
     {
         Object value = getProperty(key);
+        Class valueClass = value != null ? value.getClass() : null;
 
-        List list;
+        Object array;
 
         if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
         {
-            list = defaultValue;
-        }
-        else if (value instanceof short[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((short[]) value));
-        }
-        else if (value instanceof Short[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Short[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toShort(interpolate(it.next())));
-            }
+            // the value is null or is an empty string
+            array = defaultValue;
         }
         else
         {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toShort(interpolate(value)));
-            }
-            catch (ConversionException e)
+            if (valueClass.isArray())
             {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of shorts", e);
+                // get the class of the objects contained in the array
+                Class arrayType = valueClass.getComponentType();
+                int length = Array.getLength(value);
+
+                if (arrayType.equals(cls))
+                {
+                    // the value is an array of the same primitive type
+                    array = value;
+                }
+                else if (arrayType.equals(ClassUtils.primitiveToWrapper(cls)))
+                {
+                    // the value is an array of the wrapper type derived from the specified primitive type
+                    array = Array.newInstance(cls, length);
+
+                    for (int i = 0; i < length; i++)
+                    {
+                        Array.set(array, i, Array.get(value, i));
+                    }
+                }
+                else
+                {
+                    throw new ConversionException('\'' + key + "' (" + arrayType + ") doesn't map to a compatible array of " + cls);
+                }
+            }
+            else if (value instanceof Collection)
+            {
+                Collection values = (Collection) value;
+
+                array = Array.newInstance(cls, values.size());
+
+                Iterator it = values.iterator();
+                int i = 0;
+                while (it.hasNext())
+                {
+                    Array.set(array, i++, PropertyConverter.to(cls, interpolate(it.next()), null));
+                }
+            }
+            else
+            {
+                try
+                {
+                    // attempt to convert a single value
+                    Object convertedValue = PropertyConverter.to(cls, interpolate(value), null);
+
+                    // create an array of one element
+                    array = Array.newInstance(cls, 1);
+                    Array.set(array, 0, convertedValue);
+                }
+                catch (ConversionException e)
+                {
+                    throw new ConversionException('\'' + key + "' doesn't map to an array of " + cls, e);
+                }
             }
         }
 
-        return list;
+        return array;
     }
 
     /**
-     * Get an array of short primitives associated with the given
+     * Get a list of Boolean objects associated with the given
      * configuration key. If the key doesn't map to an existing object
-     * an empty array is returned.
+     * an empty list is returned.
      *
      * @param key The configuration key.
-     * @return The associated short array if the key is found.
+     * @return The associated Boolean list if the key is found.
      *
      * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of shorts.
+     *         object that is not a list of booleans.
      */
-    public short[] getShortArray(String key)
+    public List getBooleanList(String key)
     {
-        return getShortArray(key, new short[0]);
+        return getBooleanList(key, new ArrayList());
     }
 
     /**
-     * Get an array of short primitives associated with the given
-     * configuration key. If the key doesn't map to an existing object
-     * an empty array is returned.
+     * Get a list of Boolean objects associated with the given
+     * configuration key. If the key doesn't map to an existing object,
+     * the default value is returned.
      *
      * @param key The configuration key.
-     * @param defaultValue the default value, which will be returned if the property is not found
-     * @return The associated short array if the key is found.
+     * @param defaultValue The default value.
+     * @return The associated List of Booleans.
      *
      * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of shorts.
+     *         object that is not a list of booleans.
      */
-    public short[] getShortArray(String key, short[] defaultValue)
+    public List getBooleanList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
+         return getList(Boolean.class, key, defaultValue);
+    }
 
-        short[] array;
+    /**
+     * Get an array of boolean primitives associated with the given
+     * configuration key. If the key doesn't map to an existing object
+     * an empty array is returned.
+     *
+     * @param key The configuration key.
+     * @return The associated boolean array if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of booleans.
+     */
+    public boolean[] getBooleanArray(String key)
+    {
+        return (boolean[]) getArray(Boolean.TYPE, key);
+    }
 
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof short[])
-        {
-            array = (short[]) value;
-        }
-        else if (value instanceof Short[])
-        {
-            array = ArrayUtils.toPrimitive((Short[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            array = new short[values.size()];
+    /**
+     * Get an array of boolean primitives associated with the given
+     * configuration key. If the key doesn't map to an existing object,
+     * the default value is returned.
+     *
+     * @param key          The configuration key.
+     * @param defaultValue The default value.
+     * @return The associated boolean array if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of booleans.
+     */
+    public boolean[] getBooleanArray(String key, boolean[] defaultValue)
+    {
+        return (boolean[]) getArray(Boolean.TYPE, key, defaultValue);
+    }
 
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toShort(interpolate(it.next())).shortValue();
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                array = new short[1];
-                array[0] = PropertyConverter.toShort(interpolate(value)).shortValue();
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of shorts", e);
-            }
-        }
+    /**
+     * Get a list of Byte objects associated with the given configuration key.
+     * If the key doesn't map to an existing object an empty list is returned.
+     *
+     * @param key The configuration key.
+     * @return The associated Byte list if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of bytes.
+     */
+    public List getByteList(String key)
+    {
+        return getByteList(key, new ArrayList());
+    }
 
-        return array;
+    /**
+     * Get a list of Byte objects associated with the given configuration key.
+     * If the key doesn't map to an existing object, the default value is
+     * returned.
+     *
+     * @param key The configuration key.
+     * @param defaultValue The default value.
+     * @return The associated List of Bytes.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of bytes.
+     */
+    public List getByteList(String key, List defaultValue)
+    {
+        return getList(Byte.class, key, defaultValue);
+    }
+
+    /**
+     * Get an array of byte primitives associated with the given
+     * configuration key. If the key doesn't map to an existing object
+     * an empty array is returned.
+     *
+     * @param key The configuration key.
+     * @return The associated byte array if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of bytes.
+     */
+    public byte[] getByteArray(String key)
+    {
+        return getByteArray(key, new byte[0]);
+    }
+
+    /**
+     * Get an array of byte primitives associated with the given
+     * configuration key. If the key doesn't map to an existing object
+     * an empty array is returned.
+     *
+     * @param key The configuration key.
+     * @param defaultValue the default value, which will be returned if the property is not found
+     * @return The associated byte array if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of bytes.
+     */
+    public byte[] getByteArray(String key, byte[] defaultValue)
+    {
+        return (byte[]) getArray(Byte.TYPE, key, defaultValue);
+    }
+
+    /**
+     * Get a list of Short objects associated with the given configuration key.
+     * If the key doesn't map to an existing object an empty list is returned.
+     *
+     * @param key The configuration key.
+     * @return The associated Short list if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of shorts.
+     */
+    public List getShortList(String key)
+    {
+        return getShortList(key, new ArrayList());
+    }
+
+    /**
+     * Get a list of Short objects associated with the given configuration key.
+     * If the key doesn't map to an existing object, the default value is
+     * returned.
+     *
+     * @param key The configuration key.
+     * @param defaultValue The default value.
+     * @return The associated List of Shorts.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of shorts.
+     */
+    public List getShortList(String key, List defaultValue)
+    {
+        return getList(Short.class, key, defaultValue);
+    }
+
+    /**
+     * Get an array of short primitives associated with the given
+     * configuration key. If the key doesn't map to an existing object
+     * an empty array is returned.
+     *
+     * @param key The configuration key.
+     * @return The associated short array if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of shorts.
+     */
+    public short[] getShortArray(String key)
+    {
+        return getShortArray(key, new short[0]);
+    }
+
+    /**
+     * Get an array of short primitives associated with the given
+     * configuration key. If the key doesn't map to an existing object
+     * an empty array is returned.
+     *
+     * @param key The configuration key.
+     * @param defaultValue the default value, which will be returned if the property is not found
+     * @return The associated short array if the key is found.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of shorts.
+     */
+    public short[] getShortArray(String key, short[] defaultValue)
+    {
+        return (short[]) getArray(Short.TYPE, key, defaultValue);
     }
 
     /**
@@ -602,50 +699,7 @@
      */
     public List getIntegerList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof int[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((int[]) value));
-        }
-        else if (value instanceof Integer[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Integer[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toInteger(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toInteger(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of integers", e);
-            }
-        }
-
-        return list;
+        return getList(Integer.class, key, defaultValue);
     }
 
     /**
@@ -678,49 +732,7 @@
      */
     public int[] getIntArray(String key, int[] defaultValue)
     {
-        Object value = getProperty(key);
-
-        int[] array;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof int[])
-        {
-            array = (int[]) value;
-        }
-        else if (value instanceof Integer[])
-        {
-            array = ArrayUtils.toPrimitive((Integer[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            array = new int[values.size()];
-
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toInteger(interpolate(it.next())).intValue();
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                array = new int[1];
-                array[0] = PropertyConverter.toInteger(interpolate(value)).intValue();
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of integers", e);
-            }
-        }
-
-        return array;
+        return (int[]) getArray(Integer.TYPE, key, defaultValue);
     }
 
     /**
@@ -752,50 +764,7 @@
      */
     public List getLongList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof long[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((long[]) value));
-        }
-        else if (value instanceof Long[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Long[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toLong(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toLong(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of longs", e);
-            }
-        }
-
-        return list;
+        return getList(Long.class, key, defaultValue);
     }
 
     /**
@@ -828,49 +797,7 @@
      */
     public long[] getLongArray(String key, long[] defaultValue)
     {
-        Object value = getProperty(key);
-
-        long[] array;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof long[])
-        {
-            array = (long[]) value;
-        }
-        else if (value instanceof Long[])
-        {
-            array = ArrayUtils.toPrimitive((Long[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            array = new long[values.size()];
-
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toLong(interpolate(it.next())).longValue();
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                array = new long[1];
-                array[0] = PropertyConverter.toLong(interpolate(value)).longValue();
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of longs", e);
-            }
-        }
-
-        return array;
+        return (long[]) getArray(Long.TYPE, key, defaultValue);
     }
 
     /**
@@ -902,50 +829,7 @@
      */
     public List getFloatList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof float[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((float[]) value));
-        }
-        else if (value instanceof Float[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Float[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toFloat(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toFloat(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of floats", e);
-            }
-        }
-
-        return list;
+        return getList(Float.class, key, defaultValue);
     }
 
     /**
@@ -978,49 +862,7 @@
      */
     public float[] getFloatArray(String key, float[] defaultValue)
     {
-        Object value = getProperty(key);
-
-        float[] array;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof float[])
-        {
-            array = (float[]) value;
-        }
-        else if (value instanceof Float[])
-        {
-            array = ArrayUtils.toPrimitive((Float[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            array = new float[values.size()];
-
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toFloat(interpolate(it.next())).floatValue();
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                array = new float[1];
-                array[0] = PropertyConverter.toFloat(interpolate(value)).floatValue();
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of floats", e);
-            }
-        }
-
-        return array;
+        return (float[]) getArray(Float.TYPE, key, defaultValue);
     }
 
     /**
@@ -1053,50 +895,7 @@
      */
     public List getDoubleList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof double[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, ArrayUtils.toObject((double[]) value));
-        }
-        else if (value instanceof Double[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Double[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toDouble(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toDouble(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of doubles", e);
-            }
-        }
-
-        return list;
+        return getList(Double.class, key, defaultValue);
     }
 
     /**
@@ -1129,49 +928,7 @@
      */
     public double[] getDoubleArray(String key, double[] defaultValue)
     {
-        Object value = getProperty(key);
-
-        double[] array;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            array = defaultValue;
-        }
-        else if (value instanceof double[])
-        {
-            array = (double[]) value;
-        }
-        else if (value instanceof Double[])
-        {
-            array = ArrayUtils.toPrimitive((Double[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            array = new double[values.size()];
-
-            int i = 0;
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                array[i++] = PropertyConverter.toDouble(interpolate(it.next())).doubleValue();
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                array = new double[1];
-                array[0] = PropertyConverter.toDouble(interpolate(value)).doubleValue();
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of doubles", e);
-            }
-        }
-
-        return array;
+        return (double[]) getArray(Double.TYPE, key, defaultValue);
     }
 
     /**
@@ -1185,63 +942,25 @@
      *         object that is not a list of BigIntegers.
      */
     public List getBigIntegerList(String key)
-    {
-        return getBigIntegerList(key, new ArrayList());
-    }
-
-    /**
-     * Get a list of BigIntegers associated with the given configuration key.
-     * If the key doesn't map to an existing object, the default value is
-     * returned.
-     *
-     * @param key The configuration key.
-     * @param defaultValue The default value.
-     * @return The associated List of BigIntegers.
-     *
-     * @throws ConversionException is thrown if the key maps to an
-     *         object that is not a list of BigIntegers.
-     */
-    public List getBigIntegerList(String key, List defaultValue)
-    {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof BigInteger[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (BigInteger[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toBigInteger(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toBigInteger(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of big integers", e);
-            }
-        }
+    {
+        return getBigIntegerList(key, new ArrayList());
+    }
 
-        return list;
+    /**
+     * Get a list of BigIntegers associated with the given configuration key.
+     * If the key doesn't map to an existing object, the default value is
+     * returned.
+     *
+     * @param key The configuration key.
+     * @param defaultValue The default value.
+     * @return The associated List of BigIntegers.
+     *
+     * @throws ConversionException is thrown if the key maps to an
+     *         object that is not a list of BigIntegers.
+     */
+    public List getBigIntegerList(String key, List defaultValue)
+    {
+        return getList(BigInteger.class, key, defaultValue);
     }
 
     /**
@@ -1274,15 +993,7 @@
      */
     public BigInteger[] getBigIntegerArray(String key, BigInteger[] defaultValue)
     {
-        List list = getBigIntegerList(key);
-        if (list.isEmpty())
-        {
-            return defaultValue;
-        }
-        else
-        {
-            return (BigInteger[]) list.toArray(new BigInteger[list.size()]);
-        }
+        return (BigInteger[]) getArray(BigInteger.class, key, defaultValue);
     }
 
     /**
@@ -1314,45 +1025,7 @@
      */
     public List getBigDecimalList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof BigDecimal[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (BigDecimal[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toBigDecimal(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toBigDecimal(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of big decimals", e);
-            }
-        }
-
-        return list;
+        return getList(BigDecimal.class, key, defaultValue);
     }
 
     /**
@@ -1385,15 +1058,7 @@
      */
     public BigDecimal[] getBigDecimalArray(String key, BigDecimal[] defaultValue)
     {
-        List list = getBigDecimalList(key);
-        if (list.isEmpty())
-        {
-            return defaultValue;
-        }
-        else
-        {
-            return (BigDecimal[]) list.toArray(new BigDecimal[list.size()]);
-        }
+        return (BigDecimal[]) getArray(BigDecimal.class, key, defaultValue);
     }
 
     /**
@@ -1407,7 +1072,7 @@
      */
     public URL getURL(String key)
     {
-        return getURL(key, null);
+        return (URL) get(URL.class, key);
     }
 
     /**
@@ -1424,23 +1089,7 @@
      */
     public URL getURL(String key, URL defaultValue)
     {
-        Object value = resolveContainerStore(key);
-
-        if (value == null)
-        {
-            return defaultValue;
-        }
-        else
-        {
-            try
-            {
-                return PropertyConverter.toURL(interpolate(value));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to an URL", e);
-            }
-        }
+        return (URL) get(URL.class, key, defaultValue);
     }
 
     /**
@@ -1472,45 +1121,7 @@
      */
     public List getURLList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof URL[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (URL[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toURL(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toURL(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of URLs", e);
-            }
-        }
-
-        return list;
+        return getList(URL.class, key, defaultValue);
     }
 
     /**
@@ -1541,15 +1152,7 @@
      */
     public URL[] getURLArray(String key, URL[] defaultValue)
     {
-        List list = getURLList(key);
-        if (list.isEmpty())
-        {
-            return defaultValue;
-        }
-        else
-        {
-            return (URL[]) list.toArray(new URL[list.size()]);
-        }
+        return (URL[]) getArray(URL.class, key, defaultValue);
     }
 
     /**
@@ -1566,7 +1169,7 @@
      */
     public Date getDate(String key)
     {
-        return getDate(key, getDefaultDateFormat());
+        return (Date) get(Date.class, key);
     }
 
     /**
@@ -1582,7 +1185,19 @@
      */
     public Date getDate(String key, String format)
     {
-        return getDate(key, null, format);
+        Date value = getDate(key, null, format);
+        if (value != null)
+        {
+            return value;
+        }
+        else if (isThrowExceptionOnMissing())
+        {
+            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
+        }
+        else
+        {
+            return null;
+        }
     }
 
     /**
@@ -1719,19 +1334,13 @@
         {
             list = defaultValue;
         }
-        else if (value instanceof Date[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Date[]) value);
-        }
-        else if (value instanceof Calendar[])
+        else if (value.getClass().isArray())
         {
             list = new ArrayList();
-            Calendar[] values = (Calendar[]) value;
-
-            for (int i = 0; i < values.length; i++)
+            int length = Array.getLength(value);
+            for (int i = 0; i < length; i++)
             {
-                list.add(values[i].getTime());
+                list.add(PropertyConverter.toDate(interpolate(Array.get(value, i)), format));
             }
         }
         else if (value instanceof Collection)
@@ -1858,7 +1467,7 @@
      */
     public Calendar getCalendar(String key)
     {
-        return getCalendar(key, getDefaultDateFormat());
+        return (Calendar) get(Calendar.class, key);
     }
 
     /**
@@ -1875,7 +1484,19 @@
      */
     public Calendar getCalendar(String key, String format)
     {
-        return getCalendar(key, null, format);
+        Calendar value = getCalendar(key, null, format);
+        if (value != null)
+        {
+            return value;
+        }
+        else if (isThrowExceptionOnMissing())
+        {
+            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
+        }
+        else
+        {
+            return null;
+        }
     }
 
     /**
@@ -2012,21 +1633,13 @@
         {
             list = defaultValue;
         }
-        else if (value instanceof Calendar[])
+        else if (value.getClass().isArray())
         {
             list = new ArrayList();
-            CollectionUtils.addAll(list, (Calendar[]) value);
-        }
-        else if (value instanceof Date[])
-        {
-            list = new ArrayList();
-            Date[] values = (Date[]) value;
-
-            for (int i = 0; i < values.length; i++)
+            int length = Array.getLength(value);
+            for (int i = 0; i < length; i++)
             {
-                Calendar calendar = Calendar.getInstance();
-                calendar.setTime(values[i]);
-                list.add(calendar);
+                list.add(PropertyConverter.toCalendar(interpolate(Array.get(value, i)), format));
             }
         }
         else if (value instanceof Collection)
@@ -2161,7 +1774,7 @@
      */
     public Locale getLocale(String key)
     {
-        return getLocale(key, null);
+        return (Locale) get(Locale.class, key);
     }
 
     /**
@@ -2178,23 +1791,7 @@
      */
     public Locale getLocale(String key, Locale defaultValue)
     {
-        Object value = resolveContainerStore(key);
-
-        if (value == null)
-        {
-            return defaultValue;
-        }
-        else
-        {
-            try
-            {
-                return PropertyConverter.toLocale(interpolate(value));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a Locale", e);
-            }
-        }
+        return (Locale) get(Locale.class, key, defaultValue);
     }
 
     /**
@@ -2226,45 +1823,7 @@
      */
     public List getLocaleList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof Locale[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Locale[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toLocale(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toLocale(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of Locales", e);
-            }
-        }
-
-        return list;
+        return getList(Locale.class, key, defaultValue);
     }
 
     /**
@@ -2297,15 +1856,7 @@
      */
     public Locale[] getLocaleArray(String key, Locale[] defaultValue)
     {
-        List list = getLocaleList(key);
-        if (list.isEmpty())
-        {
-            return defaultValue;
-        }
-        else
-        {
-            return (Locale[]) list.toArray(new Locale[list.size()]);
-        }
+        return (Locale[]) getArray(Locale.class, key, defaultValue);
     }
 
     /**
@@ -2319,7 +1870,7 @@
      */
     public Color getColor(String key)
     {
-        return getColor(key, null);
+        return (Color) get(Color.class, key);
     }
 
     /**
@@ -2336,23 +1887,7 @@
      */
     public Color getColor(String key, Color defaultValue)
     {
-        Object value = resolveContainerStore(key);
-
-        if (value == null)
-        {
-            return defaultValue;
-        }
-        else
-        {
-            try
-            {
-                return PropertyConverter.toColor(interpolate(value));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a Color", e);
-            }
-        }
+        return (Color) get(Color.class, key, defaultValue);
     }
 
     /**
@@ -2384,45 +1919,7 @@
      */
     public List getColorList(String key, List defaultValue)
     {
-        Object value = getProperty(key);
-
-        List list;
-
-        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value)))
-        {
-            list = defaultValue;
-        }
-        else if (value instanceof Color[])
-        {
-            list = new ArrayList();
-            CollectionUtils.addAll(list, (Color[]) value);
-        }
-        else if (value instanceof Collection)
-        {
-            Collection values = (Collection) value;
-            list = new ArrayList();
-
-            Iterator it = values.iterator();
-            while (it.hasNext())
-            {
-                list.add(PropertyConverter.toColor(interpolate(it.next())));
-            }
-        }
-        else
-        {
-            try
-            {
-                // attempt to convert a single value
-                list = new ArrayList();
-                list.add(PropertyConverter.toColor(interpolate(value)));
-            }
-            catch (ConversionException e)
-            {
-                throw new ConversionException('\'' + key + "' doesn't map to a list of Colors", e);
-            }
-        }
-
-        return list;
+        return getList(Color.class, key, defaultValue);
     }
 
     /**
@@ -2455,15 +1952,7 @@
      */
     public Color[] getColorArray(String key, Color[] defaultValue)
     {
-        List list = getColorList(key);
-        if (list.isEmpty())
-        {
-            return defaultValue;
-        }
-        else
-        {
-            return (Color[]) list.toArray(new Color[list.size()]);
-        }
+        return (Color[]) getArray(Color.class, key, defaultValue);
     }
 
 }

Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java?view=diff&rev=529806&r1=529805&r2=529806
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java Tue Apr 17 16:46:34 2007
@@ -72,6 +72,84 @@
     }
 
     /**
+     * Converts the specified value to the target class. If the class is a
+     * primitive type (Integer.TYPE, Boolean.TYPE, etc) the value returned
+     * will use the wrapper type (Integer.class, Boolean.class, etc).
+     *
+     * @param cls   the target class of the converted value
+     * @param value the value to convert
+     * @param params optional parameters used for the conversion
+     * @return the converted value
+     * @throws ConversionException if the value is not compatible with the requested type
+     *
+     * @since 1.5
+     */
+    static Object to(Class cls, Object value, Object[] params) throws ConversionException
+    {
+        if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls))
+        {
+            return PropertyConverter.toBoolean(value);
+        }
+        else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive())
+        {
+            if (Integer.class.equals(cls) || Integer.TYPE.equals(cls))
+            {
+                return PropertyConverter.toInteger(value);
+            }
+            else if (Long.class.equals(cls) || Long.TYPE.equals(cls))
+            {
+                return PropertyConverter.toLong(value);
+            }
+            else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls))
+            {
+                return PropertyConverter.toByte(value);
+            }
+            else if (Short.class.equals(cls) || Short.TYPE.equals(cls))
+            {
+                return PropertyConverter.toShort(value);
+            }
+            else if (Float.class.equals(cls) || Float.TYPE.equals(cls))
+            {
+                return PropertyConverter.toFloat(value);
+            }
+            else if (Double.class.equals(cls) || Double.TYPE.equals(cls))
+            {
+                return PropertyConverter.toDouble(value);
+            }
+            else if (BigInteger.class.equals(cls))
+            {
+                return PropertyConverter.toBigInteger(value);
+            }
+            else if (BigDecimal.class.equals(cls))
+            {
+                return PropertyConverter.toBigDecimal(value);
+            }
+        }
+        else if (Date.class.equals(cls))
+        {
+            return PropertyConverter.toDate(value, (String) params[0]);
+        }
+        else if (Calendar.class.equals(cls))
+        {
+            return PropertyConverter.toCalendar(value, (String) params[0]);
+        }
+        else if (URL.class.equals(cls))
+        {
+            return PropertyConverter.toURL(value);
+        }
+        else if (Locale.class.equals(cls))
+        {
+            return PropertyConverter.toLocale(value);
+        }
+        else if (Color.class.equals(cls))
+        {
+            return PropertyConverter.toColor(value);
+        }
+
+        throw new ConversionException("The value '" + value + "' (" + value.getClass() + ") can't be converted to a " + cls.getName() + " object");
+    }
+
+    /**
      * Convert the specified object into a Boolean. Internally the
      * <code>org.apache.commons.lang.BooleanUtils</code> class from the
      * <a href="http://jakarta.apache.org/commons/lang/">Commons Lang</a>
@@ -277,8 +355,7 @@
      * @return the converted number
      * @throws ConversionException if the object cannot be converted
      */
-    static Number toNumber(Object value, Class targetClass)
-            throws ConversionException
+    static Number toNumber(Object value, Class targetClass) throws ConversionException
     {
         if (value instanceof Number)
         {
@@ -291,8 +368,7 @@
             {
                 try
                 {
-                    return new BigInteger(str.substring(HEX_PREFIX.length()),
-                            HEX_RADIX);
+                    return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX);
                 }
                 catch (NumberFormatException nex)
                 {
@@ -461,8 +537,7 @@
      */
     public static String escapeDelimiters(String s, char delimiter)
     {
-        return StringUtils.replace(s, String.valueOf(delimiter), LIST_ESCAPE
-                + delimiter);
+        return StringUtils.replace(s, String.valueOf(delimiter), LIST_ESCAPE + delimiter);
     }
 
     /**

Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDataConfiguration.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDataConfiguration.java?view=diff&rev=529806&r1=529805&r2=529806
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDataConfiguration.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDataConfiguration.java Tue Apr 17 16:46:34 2007
@@ -29,6 +29,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.NoSuchElementException;
 
 import junit.framework.TestCase;
 import junitx.framework.ArrayAssert;
@@ -270,6 +271,7 @@
         dates.add(date2);
         conf.addProperty("date.list6", dates);
         conf.addProperty("date.list.interpolated", "${date.string},2004-12-31");
+        conf.addPropertyDirect("date.list7", new String[] { "2004-01-01", "2004-12-31" });
 
         conf.addProperty("calendar.string", "2004-01-01");
         conf.addProperty("calendar.string.interpolated", "${calendar.string}");
@@ -286,6 +288,7 @@
         calendars.add(date2);
         conf.addProperty("calendar.list6", calendars);
         conf.addProperty("calendar.list.interpolated", "${calendar.string},2004-12-31");
+        conf.addPropertyDirect("calendar.list7", new String[] { "2004-01-01", "2004-12-31" });
     }
 
     public void testGetConfiguration()
@@ -333,6 +336,59 @@
         assertFalse("the iterator is not exhausted", it.hasNext());
     }
 
+    public void testGet()
+    {
+        try
+        {
+            conf.get(Boolean.class, "url.object", null);
+            fail("No ConversionException thrown despite the wrong type of the property");
+        }
+        catch (ConversionException e)
+        {
+            // expected
+        }
+
+        assertNull("non null object for a missing key", conf.get(Object.class, "unknownkey"));
+
+        conf.setThrowExceptionOnMissing(true);
+
+        try
+        {
+            conf.get(Object.class, "unknownkey");
+            fail("NoSuchElementException should be thrown for missing properties");
+        }
+        catch (NoSuchElementException e)
+        {
+            // expected
+        }
+    }
+
+    public void testGetArray()
+    {
+        try
+        {
+            conf.getArray(Boolean.class, "unknownkey", new URL[] {});
+            fail("No ConversionException thrown despite the wrong type of the default value");
+        }
+        catch (Exception e)
+        {
+            // expected
+        }
+    }
+
+    public void testGetPrimitiveArray()
+    {
+        try
+        {
+            conf.getArray(Boolean.TYPE, "calendar.list4");
+            fail("No ConversionException thrown despite the wrong type of the property");
+        }
+        catch (ConversionException e)
+        {
+            // expected
+        }
+    }
+
     public void testGetBooleanArray()
     {
         // missing list
@@ -1230,6 +1286,9 @@
 
         // interpolated value
         assertEquals(Color.red, conf.getColor("color.string.interpolated"));
+
+        // default value
+        assertEquals(Color.cyan, conf.getColor("unknownkey", Color.cyan));
     }
 
     public void testGetColorArray() throws Exception
@@ -1310,11 +1369,25 @@
         // missing Date
         Date defaultValue = new Date();
         assertEquals(defaultValue, conf.getDate("date", defaultValue));
+        assertNull("non null object for a missing key", conf.getDate("unknownkey", "yyyy-MM-dd"));
+
+        conf.setThrowExceptionOnMissing(true);
+
+        try
+        {
+            conf.getDate("unknownkey", "yyyy-MM-dd");
+            fail("NoSuchElementException should be thrown for missing properties");
+        }
+        catch (NoSuchElementException e)
+        {
+            // expected
+        }
 
         Date expected = format.parse("2004-01-01");
 
         // Date string
         assertEquals(expected, conf.getDate("date.string"));
+        assertEquals(expected, conf.getDate("date.string", "yyyy-MM-dd"));
 
         // Date object
         assertEquals(expected, conf.getDate("date.object"));
@@ -1372,13 +1445,11 @@
         DateFormat format = new SimpleDateFormat("MM/dd/yyyy");
         Date date1 = format.parse("01/01/2004");
         Date date2 = format.parse("12/31/2004");
-        Date[] expected = new Date[]
-        { date1, date2 };
+        Date[] expected = new Date[] { date1, date2 };
 
         conf.addProperty("date.format", "01/01/2004");
         conf.addProperty("date.format", "12/31/2004");
-        ArrayAssert.assertEquals("Wrong dates with format", expected, conf
-                .getDateArray("date.format", "MM/dd/yyyy"));
+        ArrayAssert.assertEquals("Wrong dates with format", expected, conf.getDateArray("date.format", "MM/dd/yyyy"));
     }
 
     public void testGetDateList() throws Exception
@@ -1396,6 +1467,7 @@
 
         // list of strings
         ListAssert.assertEquals(expected, conf.getDateList("date.list1"));
+        ListAssert.assertEquals(expected, conf.getList(Date.class, "date.list1"));
 
         // list of strings, comma separated
         ListAssert.assertEquals(expected, conf.getDateList("date.list2"));
@@ -1412,6 +1484,9 @@
         // list of Date objects
         ListAssert.assertEquals(expected, conf.getDateList("date.list6"));
 
+        // array of strings
+        ListAssert.assertEquals(expected, conf.getList(Date.class, "date.list7"));
+
         // list of interpolated values
         ListAssert.assertEquals(expected, conf.getDateList("date.list.interpolated"));
 
@@ -1433,12 +1508,26 @@
         Calendar defaultValue = Calendar.getInstance();
         defaultValue.setTime(new Date());
         assertEquals(defaultValue, conf.getCalendar("calendar", defaultValue));
+        assertNull("non null object for a missing key", conf.getCalendar("unknownkey", "yyyy-MM-dd"));
+
+        conf.setThrowExceptionOnMissing(true);
+
+        try
+        {
+            conf.getCalendar("unknownkey", "yyyy-MM-dd");
+            fail("NoSuchElementException should be thrown for missing properties");
+        }
+        catch (NoSuchElementException e)
+        {
+            // expected
+        }
 
         Calendar expected = Calendar.getInstance();
         expected.setTime(format.parse("2004-01-01"));
 
         // Calendar string
         assertEquals(expected, conf.getCalendar("calendar.string"));
+        assertEquals(expected, conf.getCalendar("calendar.string",  "yyyy-MM-dd"));
 
         // Calendar object
         assertEquals(expected, conf.getCalendar("calendar.object"));
@@ -1450,7 +1539,6 @@
         assertEquals(expected, conf.getCalendar("calendar.string.interpolated"));
     }
 
-
     public void testGetCalendarArray() throws Exception
     {
         DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@@ -1496,6 +1584,23 @@
         ArrayAssert.assertEquals(new Calendar[] { }, conf.getCalendarArray("empty"));
     }
 
+    public void testGetCalendarArrayWithFormat() throws Exception
+    {
+        DateFormat format = new SimpleDateFormat("MM/dd/yyyy");
+        Date date1 = format.parse("01/01/2004");
+        Date date2 = format.parse("12/31/2004");
+
+        Calendar calendar1 = Calendar.getInstance();
+        calendar1.setTime(date1);
+        Calendar calendar2 = Calendar.getInstance();
+        calendar2.setTime(date2);
+        Calendar[] expected = new Calendar[] { calendar1, calendar2 };
+
+        conf.addProperty("calendar.format", "01/01/2004");
+        conf.addProperty("calendar.format", "12/31/2004");
+        ArrayAssert.assertEquals("Wrong calendars with format", expected, conf.getCalendarArray("calendar.format", "MM/dd/yyyy"));
+    }
+
     public void testGetCalendarList() throws Exception
     {
         DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@@ -1515,6 +1620,7 @@
 
         // list of strings
         ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list1"));
+        ListAssert.assertEquals(expected, conf.getList(Calendar.class, "calendar.list1"));
 
         // list of strings, comma separated
         ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list2"));
@@ -1531,6 +1637,9 @@
         // list of Calendar objects
         ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list6"));
 
+        // array of strings
+        ListAssert.assertEquals(expected, conf.getList(Calendar.class, "calendar.list7"));
+
         // list of interpolated values
         ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list.interpolated"));
 
@@ -2041,6 +2150,26 @@
 
         try
         {
+            conf.getDate("key1", "yyyy-MM-dd");
+            fail("getDate didn't throw a ConversionException");
+        }
+        catch (ConversionException e)
+        {
+            // expected
+        }
+
+        try
+        {
+            conf.getDate("key2", "yyyy-MM-dd");
+            fail("getDate didn't throw a ConversionException");
+        }
+        catch (ConversionException e)
+        {
+            // expected
+        }
+
+        try
+        {
             conf.getDateArray("key2");
             fail("getDateArray didn't throw a ConversionException");
         }
@@ -2063,6 +2192,26 @@
         {
             conf.getDateList("key2");
             fail("getDateList didn't throw a ConversionException");
+        }
+        catch (ConversionException e)
+        {
+            // expected
+        }
+
+        try
+        {
+            conf.getCalendar("key1", "yyyy-MM-dd");
+            fail("getCalendar didn't throw a ConversionException");
+        }
+        catch (ConversionException e)
+        {
+            // expected
+        }
+
+        try
+        {
+            conf.getCalendar("key2","yyyy-MM-dd");
+            fail("getCalendar didn't throw a ConversionException");
         }
         catch (ConversionException e)
         {

Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?view=diff&rev=529806&r1=529805&r2=529806
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Tue Apr 17 16:46:34 2007
@@ -23,6 +23,15 @@
 
   <body>
     <release version="1.5-SNAPSHOT" date="in SVN" description="">
+      <action dev="ebourg" type="fix">
+        The object getters in DataConfiguration with no default value
+        (i.e getURL(key)) now throw a NoSuchElementException if the flag
+        throwExceptionOnMissing is set.
+      </action>
+      <action dev="ebourg" type="add">
+        Generic getters have been added to DataConfiguration (get(), getArray()
+        and getList())
+      </action>
       <action dev="oheger" type="fix" issue="CONFIGURATION-263">
         XMLConfiguration used to drop attributes when an element's value was a
         list. This has been fixed.



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org