Author: oheger
Date: Mon Aug 19 14:33:13 2013
New Revision: 1515446
URL: http://svn.apache.org/r1515446
Log:
Implemented the new generic get methods in AbstractConfiguration.
AbstractConfiguration now has a property of type ConversionHandler. The
implementations of the new methods delegate to this converion handler object.
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
Modified:
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java?rev=1515446&r1=1515445&r2=1515446&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
(original)
+++
commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java
Mon Aug 19 14:33:13 2013
@@ -32,6 +32,8 @@ import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.configuration.convert.ConversionException;
+import org.apache.commons.configuration.convert.ConversionHandler;
+import org.apache.commons.configuration.convert.DefaultConversionHandler;
import org.apache.commons.configuration.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration.convert.DisabledListDelimiterHandler;
import org.apache.commons.configuration.convert.PropertyConverter;
@@ -138,9 +140,16 @@ public abstract class AbstractConfigurat
/** end token */
protected static final String END_TOKEN = "}";
+ /** The default {@code ConversionHandler} instance. */
+ private static final ConversionHandler DEF_CONVERSION_HANDLER =
+ new DefaultConversionHandler();
+
/** The list delimiter handler. */
private ListDelimiterHandler listDelimiterHandler;
+ /** The conversion handler. */
+ private ConversionHandler conversionHandler;
+
/**
* Whether the configuration should throw NoSuchElementExceptions or simply
* return null when a property does not exist. Defaults to return null.
@@ -165,6 +174,7 @@ public abstract class AbstractConfigurat
setLogger(null);
installDefaultInterpolator();
listDelimiterHandler = DisabledListDelimiterHandler.INSTANCE;
+ conversionHandler = DEF_CONVERSION_HANDLER;
}
/**
@@ -204,6 +214,42 @@ public abstract class AbstractConfigurat
}
/**
+ * Returns the {@code ConversionHandler} used by this instance.
+ *
+ * @return the {@code ConversionHandler}
+ * @since 2.0
+ */
+ public ConversionHandler getConversionHandler()
+ {
+ return conversionHandler;
+ }
+
+ /**
+ * Sets the {@code ConversionHandler} to be used by this instance. The
+ * {@code ConversionHandler} is responsible for every kind of data type
+ * conversion. It is consulted by all get methods returning results in
+ * specific data types. A newly created configuration uses a default
+ * {@code ConversionHandler} implementation. This can be changed while
+ * initializing the configuration (e.g. via a builder). Note that access to
+ * this property is not synchronized.
+ *
+ * @param conversionHandler the {@code ConversionHandler} to be used (must
+ * not be <b>null</b>)
+ * @throws IllegalArgumentException if the {@code ConversionHandler} is
+ * <b>null</b>
+ * @since 2.0
+ */
+ public void setConversionHandler(ConversionHandler conversionHandler)
+ {
+ if (conversionHandler == null)
+ {
+ throw new IllegalArgumentException(
+ "ConversionHandler must not be null!");
+ }
+ this.conversionHandler = conversionHandler;
+ }
+
+ /**
* Allows to set the {@code throwExceptionOnMissing} flag. This
* flag controls the behavior of property getter methods that return
* objects if the requested property is missing. If the flag is set to
@@ -1600,52 +1646,85 @@ public abstract class AbstractConfigurat
public <T> T get(Class<T> cls, String key)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ return get(cls, key, null);
}
+ /**
+ * {@inheritDoc} This implementation delegates to the
+ * {@link ConversionHandler} to perform the actual type conversion.
+ */
public <T> T get(Class<T> cls, String key, T defaultValue)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ return ObjectUtils.defaultIfNull(
+ getConversionHandler().to(getProperty(key), cls,
+ getInterpolator()), defaultValue);
}
public Object getArray(Class<?> cls, String key)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ return getArray(cls, key, null);
}
+ /**
+ * {@inheritDoc} This implementation delegates to the
+ * {@link ConversionHandler} to perform the actual type conversion. If this
+ * results in a <b>null</b> result (because the property is undefined), the
+ * default value is returned. It is checked whether the default value is an
+ * array with the correct component type. If not, an exception is thrown.
+ *
+ * @throws IllegalArgumentException if the default value is not a
compatible
+ * array
+ */
public Object getArray(Class<?> cls, String key, Object defaultValue)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ checkDefaultValueArray(cls, defaultValue);
+ return ObjectUtils.defaultIfNull(
+ getConversionHandler().toArray(getProperty(key), cls,
+ getInterpolator()), defaultValue);
}
public <T> List<T> getList(Class<T> cls, String key)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ return getList(cls, key, null);
}
+ /**
+ * {@inheritDoc} This implementation delegates to the generic
+ * {@code getCollection()}. As target collection a newly created
+ * {@code ArrayList} is passed in.
+ */
public <T> List<T> getList(Class<T> cls, String key, List<T> defaultValue)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ List<T> result = new ArrayList<T>();
+ getCollection(cls, key, result, defaultValue);
+ return result;
}
public <T> Collection<T> getCollection(Class<T> cls, String key,
Collection<T> target)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ return getCollection(cls, key, target, null);
}
+ /**
+ * {@inheritDoc} This implementation delegates to the
+ * {@link ConversionHandler} to perform the actual conversion. If no target
+ * collection is provided, an {@code ArrayList} is created.
+ */
public <T> Collection<T> getCollection(Class<T> cls, String key,
Collection<T> target, Collection<T> defaultValue)
{
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Not yet implemented!");
+ Object src = getProperty(key);
+ if (src == null)
+ {
+ return handleDefaultCollection(target, defaultValue);
+ }
+
+ Collection<T> targetCol =
+ (target != null) ? target : new ArrayList<T>();
+ getConversionHandler().toCollection(src, cls, getInterpolator(),
+ targetCol);
+ return targetCol;
}
/**
@@ -1820,4 +1899,61 @@ public abstract class AbstractConfigurat
}
return result;
}
+
+ /**
+ * Checks an object provided as default value for the {@code getArray()}
+ * method. Throws an exception if this is not an array with the correct
+ * component type.
+ *
+ * @param cls the component class for the array
+ * @param defaultValue the default value object to be checked
+ * @throws IllegalArgumentException if this is not a valid default object
+ */
+ private static void checkDefaultValueArray(Class<?> cls, Object
defaultValue)
+ {
+ if (defaultValue != null
+ && (!defaultValue.getClass().isArray() || !cls
+ .isAssignableFrom(defaultValue.getClass()
+ .getComponentType())))
+ {
+ throw new IllegalArgumentException(
+ "The type of the default value (" + defaultValue.getClass()
+ + ")" + " is not an array of the specified class ("
+ + cls + ")");
+ }
+ }
+
+ /**
+ * Handles the default collection for a collection conversion. This method
+ * fills the target collection with the content of the default collection.
+ * Both collections may be <b>null</b>.
+ *
+ * @param target the target collection
+ * @param defaultValue the default collection
+ * @return the initialized target collection
+ */
+ private static <T> Collection<T> handleDefaultCollection(Collection<T>
target,
+ Collection<T> defaultValue)
+ {
+ Collection<T> defCol;
+ if (defaultValue != null)
+ {
+ defCol = defaultValue;
+ }
+ else
+ {
+ defCol = Collections.emptyList();
+ }
+ Collection<T> result;
+ if (target == null)
+ {
+ result = new ArrayList<T>(defCol);
+ }
+ else
+ {
+ target.addAll(defCol);
+ result = target;
+ }
+ return result;
+ }
}
Modified:
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
URL:
http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java?rev=1515446&r1=1515445&r2=1515446&view=diff
==============================================================================
---
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
(original)
+++
commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.java
Mon Aug 19 14:33:13 2013
@@ -16,7 +16,9 @@
*/
package org.apache.commons.configuration;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -30,6 +32,8 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.configuration.convert.ConversionHandler;
+import org.apache.commons.configuration.convert.DefaultConversionHandler;
import org.apache.commons.configuration.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration.convert.DisabledListDelimiterHandler;
import org.apache.commons.configuration.event.ConfigurationEvent;
@@ -631,6 +635,286 @@ public class TestAbstractConfigurationBa
}
/**
+ * Tests whether a configuration instance has a default conversion hander.
+ */
+ @Test
+ public void testDefaultConversionHandler()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ assertEquals("Wrong default conversion handler",
+ DefaultConversionHandler.class, config.getConversionHandler()
+ .getClass());
+ }
+
+ /**
+ * Tests that the default conversion handler is shared between all
+ * configuration instances.
+ */
+ @Test
+ public void testDefaultConversionHandlerSharedInstance()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ PropertiesConfiguration config2 = new PropertiesConfiguration();
+ assertSame("Multiple conversion handlers",
+ config.getConversionHandler(), config2.getConversionHandler());
+ }
+
+ /**
+ * Tests whether the conversion handler can be changed.
+ */
+ @Test
+ public void testSetDefaultConversionHandler()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ ConversionHandler handler = new DefaultConversionHandler();
+ config.setConversionHandler(handler);
+ assertSame("Handler not set", handler, config.getConversionHandler());
+ }
+
+ /**
+ * Tries to set a null value for the conversion handler.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetDefaultConversionHandlerNull()
+ {
+ new PropertiesConfiguration().setConversionHandler(null);
+ }
+
+ /**
+ * Tests the generic get() method.
+ */
+ @Test
+ public void testGet()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ Integer value = 20130816;
+ config.addProperty(KEY_PREFIX, value.toString());
+ assertEquals("Wrong result", value, config.get(Integer.class,
KEY_PREFIX));
+ }
+
+ /**
+ * Tests get() for an unknown property if no default value is provided.
+ */
+ @Test
+ public void testGetUnknownNoDefaultValue()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ assertNull("Wrong result", config.get(Integer.class, KEY_PREFIX));
+ }
+
+ /**
+ * Tests get() for an unknown property if a default value is provided.
+ */
+ @Test
+ public void testGetUnknownWithDefaultValue()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ Integer defaultValue = 2121;
+ assertEquals("Wrong result", defaultValue,
+ config.get(Integer.class, KEY_PREFIX, defaultValue));
+ }
+
+ /**
+ * Tests whether conversion to an array is possible.
+ */
+ @Test
+ public void testGetArray()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ Integer[] expected = new Integer[PROP_COUNT];
+ for (int i = 0; i < PROP_COUNT; i++)
+ {
+ config.addProperty(KEY_PREFIX, String.valueOf(i));
+ expected[i] = Integer.valueOf(i);
+ }
+ Integer[] result =
+ (Integer[]) config.getArray(Integer.class, KEY_PREFIX);
+ assertArrayEquals("Wrong result", expected, result);
+ }
+
+ /**
+ * Tests a conversion to an array of primitive types.
+ */
+ @Test
+ public void testGetArrayPrimitive()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ short[] expected = new short[PROP_COUNT];
+ for (int i = 0; i < PROP_COUNT; i++)
+ {
+ config.addProperty(KEY_PREFIX, String.valueOf(i));
+ expected[i] = (short) i;
+ }
+ short[] result =
+ (short[]) config.getArray(Short.TYPE, KEY_PREFIX, new
short[0]);
+ assertArrayEquals("Wrong result", expected, result);
+ }
+
+ /**
+ * Tests getArray() for an unknown property if no default value is
provided.
+ */
+ @Test
+ public void testGetArrayUnknownNoDefault()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ assertNull("Wrong result", config.getArray(Integer.class, KEY_PREFIX));
+ }
+
+ /**
+ * Tests getArray() for an unknown property if a default value is provided.
+ */
+ @Test
+ public void testGetArrayUnknownWithDefault()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ int[] defValue = {
+ 1, 2, 3
+ };
+ assertArrayEquals("Wrong result", defValue,
+ (int[]) config.getArray(Integer.TYPE, KEY_PREFIX, defValue));
+ }
+
+ /**
+ * Tests getArray() if the default value is not an array.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetArrayDefaultValueNotAnArray()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ config.getArray(Integer.class, KEY_PREFIX, this);
+ }
+
+ /**
+ * Tests getArray() if the default value is an array with a different
+ * component type.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetArrayDefaultValueWrongComponentClass()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ config.getArray(Integer.class, KEY_PREFIX, new short[1]);
+ }
+
+ /**
+ * Prepares a test configuration for a test for a list conversion. The
+ * configuration is populated with a list property. The returned list
+ * contains the expected list values converted to integers.
+ *
+ * @param config the test configuration
+ * @return the list with expected values
+ */
+ private static List<Integer> prepareListTest(PropertiesConfiguration
config)
+ {
+ List<Integer> expected = new ArrayList<Integer>(PROP_COUNT);
+ for (int i = 0; i < PROP_COUNT; i++)
+ {
+ config.addProperty(KEY_PREFIX, String.valueOf(i));
+ expected.add(i);
+ }
+ return expected;
+ }
+
+ /**
+ * Tests a conversion to a list.
+ */
+ @Test
+ public void testGetList()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ List<Integer> expected = prepareListTest(config);
+ List<Integer> result = config.getList(Integer.class, KEY_PREFIX);
+ assertEquals("Wrong result", expected, result);
+ }
+
+ /**
+ * Tests a conversion to a list if the property is unknown and no default
+ * value is provided.
+ */
+ @Test
+ public void testGetListUnknownNoDefault()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ assertTrue("Wrong result", config.getList(Integer.class,
KEY_PREFIX).isEmpty());
+ }
+
+ /**
+ * Tests a conversion to a list if the property is unknown and a default
+ * list is provided.
+ */
+ @Test
+ public void testGetListUnknownWithDefault()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ List<Integer> defValue = Arrays.asList(1, 2, 3);
+ assertEquals("Wrong result", defValue, config.getList(Integer.class,
KEY_PREFIX, defValue));
+ }
+
+ /**
+ * Tests a conversion to a collection.
+ */
+ @Test
+ public void testGetCollection()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ List<Integer> expected = prepareListTest(config);
+ List<Integer> result = new ArrayList<Integer>(PROP_COUNT);
+ assertSame("Wrong result", result, config.getCollection(Integer.class,
KEY_PREFIX, result));
+ assertEquals("Wrong converted content", expected, result);
+ }
+
+ /**
+ * Tests getCollection() if no target collection is provided.
+ */
+ @Test
+ public void testGetCollectionNullTarget()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ List<Integer> expected = prepareListTest(config);
+ Collection<Integer> result = config.getCollection(Integer.class,
KEY_PREFIX, null, new ArrayList<Integer>());
+ assertEquals("Wrong result", expected, result);
+ }
+
+ /**
+ * Tests whether a single value property can be converted to a collection.
+ */
+ @Test
+ public void testGetCollectionSingleValue()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ config.addProperty(KEY_PREFIX, "1");
+ List<Integer> result = new ArrayList<Integer>(1);
+ config.getCollection(Integer.class, KEY_PREFIX, result);
+ assertEquals("Wrong number of elements", 1, result.size());
+ assertEquals("Wrong element", Integer.valueOf(1), result.get(0));
+ }
+
+ /**
+ * Tests getCollection() for an unknown property if no default value is
+ * provided.
+ */
+ @Test
+ public void testGetCollectionUnknownNoDefault()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ List<Integer> result = new ArrayList<Integer>();
+ assertSame("Wrong result", result, config.getCollection(Integer.class,
KEY_PREFIX, result));
+ assertTrue("Got elements", result.isEmpty());
+ }
+
+ /**
+ * Tests getCollection() for an unknown property if a default collection is
+ * provided.
+ */
+ @Test
+ public void testGetCollectionUnknownWithDefault()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+ List<Integer> defValue = Arrays.asList(1, 2, 4, 8, 16, 32);
+ Collection<Integer> result = config.getCollection(Integer.class,
KEY_PREFIX, null, defValue);
+ assertEquals("Wrong result", defValue, result);
+ }
+
+ /**
* Creates the source configuration for testing the copy() and append()
* methods. This configuration contains keys with an odd index and values
* starting with the prefix "src". There are also some list properties.