You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2013/01/25 22:24:43 UTC

svn commit: r1438718 - in /commons/proper/configuration/trunk/src: main/java/org/apache/commons/configuration/builder/ main/java/org/apache/commons/configuration/builder/combined/ test/java/org/apache/commons/configuration/builder/ test/java/org/apache...

Author: oheger
Date: Fri Jan 25 21:24:42 2013
New Revision: 1438718

URL: http://svn.apache.org/viewvc?rev=1438718&view=rev
Log:
BasicBuilderParameters now provides a method for obtaining an InterpolatorSpecification object; the method for fetching a ConfigurationInterpolator was dropped.
MultiFileConfigurationBuilder uses this method for obtaining its ConfigurationInterpolator.

Modified:
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicBuilderParameters.java
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicBuilderParameters.java
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicBuilderParameters.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicBuilderParameters.java?rev=1438718&r1=1438717&r2=1438718&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicBuilderParameters.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/BasicBuilderParameters.java Fri Jan 25 21:24:42 2013
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
+import org.apache.commons.configuration.interpol.InterpolatorSpecification;
 import org.apache.commons.configuration.interpol.Lookup;
 import org.apache.commons.logging.Log;
 
@@ -255,19 +256,30 @@ public class BasicBuilderParameters impl
     }
 
     /**
-     * Obtains the {@code ConfigurationInterpolator} from the given map with
-     * parameters. If such an object is stored in the map under the correct key,
-     * it is returned. Otherwise, result is <b>null</b>.
+     * Obtains a specification for a {@link ConfigurationInterpolator} from the
+     * specified map with parameters. All properties related to interpolation
+     * are evaluated and added to the specification object.
      *
      * @param params the map with parameters (must not be <b>null</b>)
-     * @return the {@code ConfigurationInterpolator} obtained from this map or
-     *         <b>null</b>
-     * @throws NullPointerException if the map is <b>null</b>
+     * @return an {@code InterpolatorSpecification} object constructed with data
+     *         from the map
+     * @throws IllegalArgumentException if the map is <b>null</b> or contains
+     *         invalid data
      */
-    public static ConfigurationInterpolator fetchInterpolator(
+    public static InterpolatorSpecification fetchInterpolatorSpecification(
             Map<String, Object> params)
     {
-        return (ConfigurationInterpolator) params.get(PROP_INTERPOLATOR);
+        checkParameters(params);
+        return new InterpolatorSpecification.Builder()
+                .withInterpolator(
+                        fetchParameter(params, PROP_INTERPOLATOR,
+                                ConfigurationInterpolator.class))
+                .withParentInterpolator(
+                        fetchParameter(params, PROP_PARENT_INTERPOLATOR,
+                                ConfigurationInterpolator.class))
+                .withPrefixLookups(fetchAndCheckPrefixLookups(params))
+                .withDefaultLookups(fetchAndCheckDefaultLookups(params))
+                .create();
     }
 
     /**
@@ -362,24 +374,165 @@ public class BasicBuilderParameters impl
      *
      * @param params the map with parameters to be passed to the caller
      */
-    public static void createDefensiveCopies(HashMap<String, Object> params)
+    private static void createDefensiveCopies(HashMap<String, Object> params)
     {
-        // This is safe to case because we have full control over the map
-        // and thus know the types of the contained values
-        @SuppressWarnings("unchecked")
         Map<String, ? extends Lookup> prefixLookups =
-                (Map<String, ? extends Lookup>) params.get(PROP_PREFIX_LOOKUPS);
+                fetchPrefixLookups(params);
         if (prefixLookups != null)
         {
             params.put(PROP_PREFIX_LOOKUPS, new HashMap<String, Lookup>(
                     prefixLookups));
         }
+        Collection<? extends Lookup> defLookups = fetchDefaultLookups(params);
+        if (defLookups != null)
+        {
+            params.put(PROP_DEFAULT_LOOKUPS, new ArrayList<Lookup>(defLookups));
+        }
+    }
+
+    /**
+     * Obtains the map with prefix lookups from the parameters map.
+     *
+     * @param params the map with parameters
+     * @return the map with prefix lookups (may be <b>null</b>)
+     */
+    private static Map<String, ? extends Lookup> fetchPrefixLookups(
+            Map<String, Object> params)
+    {
+        // This is safe to cast because we either have full control over the map
+        // and thus know the types of the contained values or have checked
+        // the content before
+        @SuppressWarnings("unchecked")
+        Map<String, ? extends Lookup> prefixLookups =
+                (Map<String, ? extends Lookup>) params.get(PROP_PREFIX_LOOKUPS);
+        return prefixLookups;
+    }
+
+    /**
+     * Tests whether the passed in map with parameters contains a map with
+     * prefix lookups. This method is used if the parameters map is from an
+     * insecure source and we cannot be sure that it contains valid data.
+     * Therefore, we have to map that the key for the prefix lookups actually
+     * points to a map containing keys and values of expected data types.
+     *
+     * @param params the parameters map
+     * @return the obtained map with prefix lookups
+     * @throws IllegalArgumentException if the map contains invalid data
+     */
+    private static Map<String, ? extends Lookup> fetchAndCheckPrefixLookups(
+            Map<String, Object> params)
+    {
+        Map<?, ?> prefixes =
+                fetchParameter(params, PROP_PREFIX_LOOKUPS, Map.class);
+        if (prefixes == null)
+        {
+            return null;
+        }
+
+        for (Map.Entry<?, ?> e : prefixes.entrySet())
+        {
+            if (!(e.getKey() instanceof String)
+                    || !(e.getValue() instanceof Lookup))
+            {
+                throw new IllegalArgumentException(
+                        "Map with prefix lookups contains invalid data: "
+                                + prefixes);
+            }
+        }
+        return fetchPrefixLookups(params);
+    }
+
+    /**
+     * Obtains the collection with default lookups from the parameters map.
+     *
+     * @param params the map with parameters
+     * @return the collection with default lookups (may be <b>null</b>)
+     */
+    private static Collection<? extends Lookup> fetchDefaultLookups(
+            Map<String, Object> params)
+    {
+        // This is safe to cast because we either have full control over the map
+        // and thus know the types of the contained values or have checked
+        // the content before
         @SuppressWarnings("unchecked")
         Collection<? extends Lookup> defLookups =
                 (Collection<? extends Lookup>) params.get(PROP_DEFAULT_LOOKUPS);
-        if (defLookups != null)
+        return defLookups;
+    }
+
+    /**
+     * Tests whether the passed in map with parameters contains a valid
+     * collection with default lookups. This method works like
+     * {@link #fetchAndCheckPrefixLookups(Map)}, but tests the default lookups
+     * collection.
+     *
+     * @param params the map with parameters
+     * @return the collection with default lookups (may be <b>null</b>)
+     * @throws IllegalArgumentException if invalid data is found
+     */
+    private static Collection<? extends Lookup> fetchAndCheckDefaultLookups(
+            Map<String, Object> params)
+    {
+        Collection<?> col =
+                fetchParameter(params, PROP_DEFAULT_LOOKUPS, Collection.class);
+        if (col == null)
         {
-            params.put(PROP_DEFAULT_LOOKUPS, new ArrayList<Lookup>(defLookups));
+            return null;
+        }
+
+        for (Object o : col)
+        {
+            if (!(o instanceof Lookup))
+            {
+                throw new IllegalArgumentException(
+                        "Collection with default lookups contains invalid data: "
+                                + col);
+            }
+        }
+        return fetchDefaultLookups(params);
+    }
+
+    /**
+     * Obtains a parameter from a map and performs a type check.
+     *
+     * @param params the map with parameters
+     * @param key the key of the parameter
+     * @param expClass the expected class of the parameter value
+     * @param <T> the parameter type
+     * @return the value of the parameter in the correct data type
+     * @throws IllegalArgumentException if the parameter is not of the expected
+     *         type
+     */
+    private static <T> T fetchParameter(Map<String, Object> params, String key,
+            Class<T> expClass)
+    {
+        Object value = params.get(key);
+        if (value == null)
+        {
+            return null;
+        }
+        if (!expClass.isInstance(value))
+        {
+            throw new IllegalArgumentException(String.format(
+                    "Parameter %s is not of type %s!", key,
+                    expClass.getSimpleName()));
+        }
+        return expClass.cast(value);
+    }
+
+    /**
+     * Checks whether a map with parameters is present. Throws an exception if
+     * not.
+     *
+     * @param params the map with parameters to check
+     * @throws IllegalArgumentException if the map is <b>null</b>
+     */
+    private static void checkParameters(Map<String, Object> params)
+    {
+        if (params == null)
+        {
+            throw new IllegalArgumentException(
+                    "Parameters map must not be null!");
         }
     }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java?rev=1438718&r1=1438717&r2=1438718&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/MultiFileConfigurationBuilder.java Fri Jan 25 21:24:42 2013
@@ -20,6 +20,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
@@ -34,6 +35,7 @@ import org.apache.commons.configuration.
 import org.apache.commons.configuration.event.ConfigurationErrorListener;
 import org.apache.commons.configuration.event.ConfigurationListener;
 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
+import org.apache.commons.configuration.interpol.InterpolatorSpecification;
 import org.apache.commons.lang3.concurrent.ConcurrentUtils;
 
 /**
@@ -87,6 +89,10 @@ public class MultiFileConfigurationBuild
     private final ConcurrentMap<String, FileBasedConfigurationBuilder<T>> managedBuilders =
             new ConcurrentHashMap<String, FileBasedConfigurationBuilder<T>>();
 
+    /** Stores the {@code ConfigurationInterpolator} object. */
+    private final AtomicReference<ConfigurationInterpolator> interpolator =
+            new AtomicReference<ConfigurationInterpolator>();
+
     /**
      * A specialized builder listener which gets registered at all managed
      * builders. This listener just propagates notifications from managed
@@ -180,7 +186,7 @@ public class MultiFileConfigurationBuild
         {
             throw new ConfigurationException("No file name pattern is set!");
         }
-        String fileName = constructFileName(params, multiParams);
+        String fileName = constructFileName(multiParams);
 
         FileBasedConfigurationBuilder<T> builder =
                 getManagedBuilders().get(fileName);
@@ -280,25 +286,73 @@ public class MultiFileConfigurationBuild
             b.removeBuilderListener(managedBuilderDelegationListener);
         }
         getManagedBuilders().clear();
+        interpolator.set(null);
         super.resetParameters();
     }
 
     /**
+     * Returns the {@code ConfigurationInterpolator} used by this instance. This
+     * is the object used for evaluating the file name pattern. It is created on
+     * demand.
+     *
+     * @return the {@code ConfigurationInterpolator}
+     */
+    protected ConfigurationInterpolator getInterpolator()
+    {
+        ConfigurationInterpolator result;
+        boolean done;
+
+        // This might create multiple instances under high load,
+        // however, always the same instance is returned.
+        do
+        {
+            result = interpolator.get();
+            if (result != null)
+            {
+                done = true;
+            }
+            else
+            {
+                result = createInterpolator();
+                done = interpolator.compareAndSet(null, result);
+            }
+        } while (!done);
+
+        return result;
+    }
+
+    /**
+     * Creates the {@code ConfigurationInterpolator} to be used by this
+     * instance. This method is called when a file name is to be constructed,
+     * but no current {@code ConfigurationInterpolator} instance is available.
+     * It obtains an instance from this builder's parameters. If no properties
+     * of the {@code ConfigurationInterpolator} are specified in the parameters,
+     * a default instance without lookups is returned (which is probably not
+     * very helpful).
+     *
+     * @return the {@code ConfigurationInterpolator} to be used
+     */
+    protected ConfigurationInterpolator createInterpolator()
+    {
+        InterpolatorSpecification spec =
+                BasicBuilderParameters
+                        .fetchInterpolatorSpecification(getParameters());
+        return ConfigurationInterpolator.fromSpecification(spec);
+    }
+
+    /**
      * Determines the file name of a configuration based on the file name
      * pattern. This method is called on every access to this builder's
      * configuration. It obtains the {@link ConfigurationInterpolator} from this
      * builder's parameters and uses it to interpolate the file name pattern.
      *
-     * @param paramsMap the map with the current parameters of this builder
      * @param multiParams the parameters object for this builder
      * @return the name of the configuration file to be loaded
      */
-    protected String constructFileName(Map<String, Object> paramsMap,
+    protected String constructFileName(
             MultiFileBuilderParametersImpl multiParams)
     {
-        ConfigurationInterpolator ci =
-                BasicBuilderParameters.fetchInterpolator(paramsMap);
-        // TODO Make this more generic, handle missing CI
+        ConfigurationInterpolator ci = getInterpolator();
         return String.valueOf(ci.interpolate(multiParams.getFilePattern()));
     }
 

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicBuilderParameters.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicBuilderParameters.java?rev=1438718&r1=1438717&r2=1438718&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicBuilderParameters.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/TestBasicBuilderParameters.java Fri Jan 25 21:24:42 2013
@@ -30,6 +30,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
+import org.apache.commons.configuration.interpol.InterpolatorSpecification;
 import org.apache.commons.configuration.interpol.Lookup;
 import org.apache.commons.logging.Log;
 import org.easymock.EasyMock;
@@ -278,28 +279,124 @@ public class TestBasicBuilderParameters
     }
 
     /**
-     * Tests fetchInterpolator() if the map does not contain an object.
+     * Tests whether a specification object for interpolation can be obtained.
      */
     @Test
-    public void testFetchInterpolatorNotFound()
+    public void testFetchInterpolatorSpecification()
     {
-        Map<String, Object> params = new HashMap<String, Object>();
-        assertNull("Got an interpolator",
-                BasicBuilderParameters.fetchInterpolator(params));
+        ConfigurationInterpolator parent =
+                EasyMock.createMock(ConfigurationInterpolator.class);
+        Lookup l1 = EasyMock.createMock(Lookup.class);
+        Lookup l2 = EasyMock.createMock(Lookup.class);
+        Lookup l3 = EasyMock.createMock(Lookup.class);
+        Map<String, Lookup> prefixLookups = new HashMap<String, Lookup>();
+        prefixLookups.put("p1", l1);
+        prefixLookups.put("p2", l2);
+        Collection<Lookup> defLookups = Collections.singleton(l3);
+        params.setParentInterpolator(parent);
+        params.setPrefixLookups(prefixLookups);
+        params.setDefaultLookups(defLookups);
+        Map<String, Object> map = params.getParameters();
+        InterpolatorSpecification spec =
+                BasicBuilderParameters.fetchInterpolatorSpecification(map);
+        assertSame("Wrong parent", parent, spec.getParentInterpolator());
+        assertEquals("Wrong prefix lookups", prefixLookups,
+                spec.getPrefixLookups());
+        assertEquals("Wrong number of default lookups", 1, spec
+                .getDefaultLookups().size());
+        assertTrue("Wrong default lookup", spec.getDefaultLookups()
+                .contains(l3));
     }
 
     /**
-     * Tests whether a {@code ConfigurationInterpolator} can be obtained from a
-     * parameters map.
+     * Tests whether an InterpolatorSpecification can be fetched if a
+     * ConfigurationInterpolator is present.
      */
     @Test
-    public void testFetchInterpolatorFound()
+    public void testFetchInterpolatorSpecificationWithInterpolator()
     {
-        ConfigurationInterpolator ci = new ConfigurationInterpolator();
+        ConfigurationInterpolator ci =
+                EasyMock.createMock(ConfigurationInterpolator.class);
         params.setInterpolator(ci);
-        Map<String, Object> map = params.getParameters();
-        assertSame("Wrong interpolator", ci,
-                BasicBuilderParameters.fetchInterpolator(map));
+        InterpolatorSpecification spec =
+                BasicBuilderParameters.fetchInterpolatorSpecification(params
+                        .getParameters());
+        assertSame("Wrong interpolator", ci, spec.getInterpolator());
+        assertNull("Got a parent", spec.getParentInterpolator());
+    }
+
+    /**
+     * Tests fetchInterpolatorSpecification() if the map contains a property of
+     * an invalid data type.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testFetchInterpolatorSpecificationInvalidDataType()
+    {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("interpolator", this);
+        BasicBuilderParameters.fetchInterpolatorSpecification(map);
+    }
+
+    /**
+     * Tests fetchInterpolatorSpecification() if the map with prefix lookups
+     * contains an invalid key.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testFetchInterpolatorSpecificationInvalidMapKey()
+    {
+        Map<String, Object> map = new HashMap<String, Object>();
+        Map<Object, Object> prefix = new HashMap<Object, Object>();
+        prefix.put(42, EasyMock.createMock(Lookup.class));
+        map.put("prefixLookups", prefix);
+        BasicBuilderParameters.fetchInterpolatorSpecification(map);
+    }
+
+    /**
+     * Tests fetchInterpolatorSpecification() if the map with prefix lookups
+     * contains an invalid value.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testFetchInterpolatorSpecificationInvalidMapValue()
+    {
+        Map<String, Object> map = new HashMap<String, Object>();
+        Map<Object, Object> prefix = new HashMap<Object, Object>();
+        prefix.put("test", this);
+        map.put("prefixLookups", prefix);
+        BasicBuilderParameters.fetchInterpolatorSpecification(map);
+    }
+
+    /**
+     * Tests fetchInterpolatorSpecification() if the collection with default
+     * lookups contains an invalid value.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testFetchInterpolatorSpecificationInvalidCollectionValue()
+    {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("defaultLookups", Collections.singleton("not a lookup"));
+        BasicBuilderParameters.fetchInterpolatorSpecification(map);
+    }
+
+    /**
+     * Tests that an empty map does not cause any problems.
+     */
+    @Test
+    public void testFetchInterpolatorSpecificationEmpty()
+    {
+        InterpolatorSpecification spec =
+                BasicBuilderParameters.fetchInterpolatorSpecification(params
+                        .getParameters());
+        assertNull("Got an interpolator", spec.getInterpolator());
+        assertTrue("Got lookups", spec.getDefaultLookups().isEmpty());
+    }
+
+    /**
+     * Tries to obtain an {@code InterpolatorSpecification} from a null map.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testFetchInterpolatorSpecificationNull()
+    {
+        BasicBuilderParameters.fetchInterpolatorSpecification(null);
     }
 
     /**

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java?rev=1438718&r1=1438717&r2=1438718&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestMultiFileConfigurationBuilder.java Fri Jan 25 21:24:42 2013
@@ -18,6 +18,7 @@ package org.apache.commons.configuration
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
@@ -25,6 +26,7 @@ import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.XMLConfiguration;
@@ -36,6 +38,7 @@ import org.apache.commons.configuration.
 import org.apache.commons.configuration.event.ConfigurationErrorListener;
 import org.apache.commons.configuration.event.ConfigurationListener;
 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
+import org.apache.commons.configuration.interpol.DefaultLookups;
 import org.apache.commons.configuration.tree.ExpressionEngine;
 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
 import org.easymock.EasyMock;
@@ -119,6 +122,30 @@ public class TestMultiFileConfigurationB
     }
 
     /**
+     * Tests whether a {@code ConfigurationInterpolator} is created from
+     * properties defined in the parameters object if necessary.
+     */
+    @Test
+    public void testInterpolatorFromParameters() throws ConfigurationException
+    {
+        BasicBuilderParameters params =
+                new MultiFileBuilderParametersImpl().setFilePattern(PATTERN)
+                        .setPrefixLookups(
+                                Collections.singletonMap(
+                                        DefaultLookups.SYSTEM_PROPERTIES
+                                                .getPrefix(),
+                                        DefaultLookups.SYSTEM_PROPERTIES
+                                                .getLookup()));
+        MultiFileConfigurationBuilder<XMLConfiguration> builder =
+                new MultiFileConfigurationBuilder<XMLConfiguration>(
+                        XMLConfiguration.class);
+        builder.configure(params);
+        switchToConfig(1);
+        assertEquals("Wrong property", 15,
+                builder.getConfiguration().getInt("rowsPerPage"));
+    }
+
+    /**
      * Tests whether a managed configuration is properly initialized.
      */
     @Test
@@ -320,6 +347,25 @@ public class TestMultiFileConfigurationB
     }
 
     /**
+     * Tests whether the ConfigurationInterpolator is reset, too.
+     */
+    @Test
+    public void testInterpolatorReset()
+    {
+        BasicBuilderParameters params =
+                new MultiFileBuilderParametersImpl().setFilePattern(PATTERN);
+        MultiFileConfigurationBuilder<XMLConfiguration> builder =
+                new MultiFileConfigurationBuilder<XMLConfiguration>(
+                        XMLConfiguration.class);
+        builder.configure(params);
+        ConfigurationInterpolator interpolator = builder.getInterpolator();
+        assertNotNull("No interpolator", interpolator);
+        builder.resetParameters();
+        assertNotSame("No new interpolator", interpolator,
+                builder.getInterpolator());
+    }
+
+    /**
      * Tests whether builder listeners are handled correctly.
      */
     @Test