Merge branch 'release'
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1fae428..ed98e60 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -23,6 +23,12 @@
     <author email="dev@commons.apache.org">Apache Commons Community</author>
   </properties>
   <body>
+    <release version="2.10.2" date="YYYY-MM-DD" description="Minor release with new features and updated dependencies; requires Java 8 or above.">
+      <!-- FIX -->
+      <action type="fix" dev="ggregory" due-to="Gary Gregory">Fail-fast with a NullPointerException if DataConfiguration.DataConfiguration(Configuration) is called with null.</action>
+      <action type="fix" dev="ggregory" due-to="Gary Gregory">Fail-fast with a NullPointerException if XMLPropertiesConfiguration.XMLPropertiesConfiguration(Element) is called with null.</action>
+      <action type="fix" dev="ggregory" due-to="Gary Gregory">Fail-fast with a NullPointerException if a SubsetConfiguration constructor is called with a null Configuration.</action>
+    </release>
     <release version="2.10.1" date="2024-03-17" description="Minor release with new features and updated dependencies; requires Java 8 or above.">
       <!-- FIX -->
       <action type="fix" issue="CONFIGURATION-839" dev="ggregory" due-to="Bob Marinier, Gary Gregory">java.lang.module.FindException: Module servlet.api not found.</action>
diff --git a/src/main/java/org/apache/commons/configuration2/CompositeConfiguration.java b/src/main/java/org/apache/commons/configuration2/CompositeConfiguration.java
index 129aff7..53beae5 100644
--- a/src/main/java/org/apache/commons/configuration2/CompositeConfiguration.java
+++ b/src/main/java/org/apache/commons/configuration2/CompositeConfiguration.java
@@ -60,6 +60,7 @@
  * </p>
  */
 public class CompositeConfiguration extends AbstractConfiguration implements Cloneable {
+
     /** List holding all the configuration */
     private List<Configuration> configList = new LinkedList<>();
 
@@ -89,9 +90,9 @@
      * @param inMemoryConfiguration the in memory configuration to use
      */
     public CompositeConfiguration(final Configuration inMemoryConfiguration) {
-        configList.clear();
+        this.configList.clear();
         this.inMemoryConfiguration = inMemoryConfiguration;
-        configList.add(inMemoryConfiguration);
+        this.configList.add(inMemoryConfiguration);
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/configuration2/DataConfiguration.java b/src/main/java/org/apache/commons/configuration2/DataConfiguration.java
index 574256f..9960971 100644
--- a/src/main/java/org/apache/commons/configuration2/DataConfiguration.java
+++ b/src/main/java/org/apache/commons/configuration2/DataConfiguration.java
@@ -29,6 +29,8 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.function.Supplier;
 
 import org.apache.commons.configuration2.convert.ConversionHandler;
 import org.apache.commons.configuration2.convert.DefaultConversionHandler;
@@ -145,8 +147,8 @@
      * @param configuration the wrapped configuration
      */
     public DataConfiguration(final Configuration configuration) {
-        this.configuration = configuration;
-        dataConversionHandler = new DataConversionHandler();
+        this.configuration = Objects.requireNonNull(configuration);
+        this.dataConversionHandler = new DataConversionHandler();
     }
 
     /**
@@ -195,6 +197,15 @@
         return configuration.containsKey(key);
     }
 
+    private <R> R applyTempDateFormat(final String format, final Supplier<R> supplier) {
+        TEMP_DATE_FORMAT.set(format);
+        try {
+            return supplier.get();
+        } finally {
+            TEMP_DATE_FORMAT.remove();
+        }
+    }
+
     @Override
     protected void clearPropertyDirect(final String key) {
         configuration.clearProperty(key);
@@ -918,12 +929,7 @@
      * @throws ConversionException is thrown if the key maps to an object that is not a Date.
      */
     public Date getDate(final String key, final Date defaultValue, final String format) {
-        TEMP_DATE_FORMAT.set(format);
-        try {
-            return get(Date.class, key, defaultValue);
-        } finally {
-            TEMP_DATE_FORMAT.remove();
-        }
+        return applyTempDateFormat(format, () -> get(Date.class, key, defaultValue));
     }
 
     public List<Date> getDateList(final String key) {
@@ -972,12 +978,7 @@
      * @throws ConversionException is thrown if the key maps to an object that is not a list of Dates.
      */
     public List<Date> getDateList(final String key, final List<Date> defaultValue, final String format) {
-        TEMP_DATE_FORMAT.set(format);
-        try {
-            return getList(Date.class, key, defaultValue);
-        } finally {
-            TEMP_DATE_FORMAT.remove();
-        }
+        return applyTempDateFormat(format, () -> getList(Date.class, key, defaultValue));
     }
 
     /**
@@ -1036,12 +1037,7 @@
      * @throws ConversionException is thrown if the key maps to an object that is not a list of Dates.
      */
     public Date[] getDateArray(final String key, final Date[] defaultValue, final String format) {
-        TEMP_DATE_FORMAT.set(format);
-        try {
-            return get(Date[].class, key, defaultValue);
-        } finally {
-            TEMP_DATE_FORMAT.remove();
-        }
+        return applyTempDateFormat(format, () -> get(Date[].class, key, defaultValue));
     }
 
     /**
@@ -1106,12 +1102,7 @@
      * @throws ConversionException is thrown if the key maps to an object that is not a Calendar.
      */
     public Calendar getCalendar(final String key, final Calendar defaultValue, final String format) {
-        TEMP_DATE_FORMAT.set(format);
-        try {
-            return get(Calendar.class, key, defaultValue);
-        } finally {
-            TEMP_DATE_FORMAT.remove();
-        }
+        return applyTempDateFormat(format, () -> get(Calendar.class, key, defaultValue));
     }
 
     /**
@@ -1171,12 +1162,7 @@
      * @throws ConversionException is thrown if the key maps to an object that is not a list of Calendars.
      */
     public List<Calendar> getCalendarList(final String key, final List<Calendar> defaultValue, final String format) {
-        TEMP_DATE_FORMAT.set(format);
-        try {
-            return getList(Calendar.class, key, defaultValue);
-        } finally {
-            TEMP_DATE_FORMAT.remove();
-        }
+        return applyTempDateFormat(format, () -> getList(Calendar.class, key, defaultValue));
     }
 
     /**
@@ -1238,12 +1224,7 @@
      * @throws ConversionException is thrown if the key maps to an object that is not a list of Calendars.
      */
     public Calendar[] getCalendarArray(final String key, final Calendar[] defaultValue, final String format) {
-        TEMP_DATE_FORMAT.set(format);
-        try {
-            return get(Calendar[].class, key, defaultValue);
-        } finally {
-            TEMP_DATE_FORMAT.remove();
-        }
+        return applyTempDateFormat(format, () -> get(Calendar[].class, key, defaultValue));
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/configuration2/MapConfiguration.java b/src/main/java/org/apache/commons/configuration2/MapConfiguration.java
index c42591e..4319bdf 100644
--- a/src/main/java/org/apache/commons/configuration2/MapConfiguration.java
+++ b/src/main/java/org/apache/commons/configuration2/MapConfiguration.java
@@ -100,7 +100,7 @@
      * @since 1.8
      */
     public MapConfiguration(final Properties props) {
-        map = convertPropertiesToMap(props);
+        map = toMap(props);
     }
 
     /**
@@ -220,7 +220,7 @@
      * @return a newly created map with all string keys of the properties
      */
     @SuppressWarnings("unchecked")
-    private static Map<String, Object> convertPropertiesToMap(final Properties props) {
+    private static Map<String, Object> toMap(final Properties props) {
         @SuppressWarnings("rawtypes")
         final Map map = props;
         return map;
diff --git a/src/main/java/org/apache/commons/configuration2/SubsetConfiguration.java b/src/main/java/org/apache/commons/configuration2/SubsetConfiguration.java
index fd87053..5bc63db 100644
--- a/src/main/java/org/apache/commons/configuration2/SubsetConfiguration.java
+++ b/src/main/java/org/apache/commons/configuration2/SubsetConfiguration.java
@@ -18,6 +18,7 @@
 package org.apache.commons.configuration2;
 
 import java.util.Iterator;
+import java.util.Objects;
 
 import org.apache.commons.configuration2.convert.ListDelimiterHandler;
 import org.apache.commons.lang3.StringUtils;
@@ -59,14 +60,10 @@
      * @param parent The parent configuration (must not be <b>null</b>)
      * @param prefix The prefix used to select the properties
      * @param delimiter The prefix delimiter
-     * @throws IllegalArgumentException if the parent configuration is <b>null</b>
+     * @throws NullPointerException if the parent configuration is <b>null</b>
      */
     public SubsetConfiguration(final Configuration parent, final String prefix, final String delimiter) {
-        if (parent == null) {
-            throw new IllegalArgumentException("Parent configuration must not be null!");
-        }
-
-        this.parent = parent;
+        this.parent = Objects.requireNonNull(parent, "parent");
         this.prefix = prefix;
         this.delimiter = delimiter;
         initInterpolator();
diff --git a/src/main/java/org/apache/commons/configuration2/XMLPropertiesConfiguration.java b/src/main/java/org/apache/commons/configuration2/XMLPropertiesConfiguration.java
index 645ee6c..953dd54 100644
--- a/src/main/java/org/apache/commons/configuration2/XMLPropertiesConfiguration.java
+++ b/src/main/java/org/apache/commons/configuration2/XMLPropertiesConfiguration.java
@@ -23,6 +23,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
@@ -91,14 +92,14 @@
     }
 
     /**
-     * Creates and loads the xml properties from the specified DOM node.
+     * Creates and loads the XML properties from the specified DOM node.
      *
-     * @param element The DOM element
-     * @throws ConfigurationException Error while loading the properties file
+     * @param element The non-null DOM element.
+     * @throws ConfigurationException Error while loading the Element.
      * @since 2.0
      */
     public XMLPropertiesConfiguration(final Element element) throws ConfigurationException {
-        this.load(element);
+        load(Objects.requireNonNull(element, "element"));
     }
 
     /**
diff --git a/src/test/java/org/apache/commons/configuration2/NonCloneableConfiguration.java b/src/test/java/org/apache/commons/configuration2/NonCloneableConfiguration.java
index 33e6118..b8899a6 100644
--- a/src/test/java/org/apache/commons/configuration2/NonCloneableConfiguration.java
+++ b/src/test/java/org/apache/commons/configuration2/NonCloneableConfiguration.java
@@ -23,15 +23,18 @@
  * for testing implementations of clone() methods. It does not make much sense otherwise; all methods are just dummies.
  */
 public class NonCloneableConfiguration extends AbstractConfiguration {
+
     /**
      * Dummy implementation of this method.
      */
     @Override
     protected void addPropertyDirect(final String key, final Object value) {
+        // noop
     }
 
     @Override
     protected void clearPropertyDirect(final String key) {
+        // noop
     }
 
     /**
diff --git a/src/test/java/org/apache/commons/configuration2/TestDataConfiguration.java b/src/test/java/org/apache/commons/configuration2/TestDataConfiguration.java
index c3d3a84..4c53bcf 100644
--- a/src/test/java/org/apache/commons/configuration2/TestDataConfiguration.java
+++ b/src/test/java/org/apache/commons/configuration2/TestDataConfiguration.java
@@ -1977,9 +1977,12 @@
         final DataConfiguration conf = new DataConfiguration(baseconf);
 
         assertTrue(conf.isEmpty());
-
         baseconf.setProperty("foo", "bar");
-
         assertFalse(conf.isEmpty());
     }
+
+    @Test
+    public void testNullConfiguration() {
+        assertThrows(NullPointerException.class, () -> new DataConfiguration(null));
+    }
 }
diff --git a/src/test/java/org/apache/commons/configuration2/TestSubsetConfiguration.java b/src/test/java/org/apache/commons/configuration2/TestSubsetConfiguration.java
index 4ba2456..c3a6ba1 100644
--- a/src/test/java/org/apache/commons/configuration2/TestSubsetConfiguration.java
+++ b/src/test/java/org/apache/commons/configuration2/TestSubsetConfiguration.java
@@ -60,6 +60,14 @@
         assertFalse(config.isEmpty());
     }
 
+    /**
+     * Tries to create an instance without a parent configuration.
+     */
+    @Test
+    public void testConstructNullParent() {
+        assertThrows(NullPointerException.class, () -> new SubsetConfiguration(null, ""));
+    }
+
     @Test
     public void testGetChildKey() {
         final Configuration conf = new BaseConfiguration();
@@ -170,14 +178,6 @@
         assertFalse(subset.containsKey("ng.key2"));
     }
 
-    /**
-     * Tries to create an instance without a parent configuration.
-     */
-    @Test
-    public void testInitNoParent() {
-        assertThrows(IllegalArgumentException.class, () -> new SubsetConfiguration(null, ""));
-    }
-
     @Test
     public void testInterpolationForKeysOfTheParent() {
         final BaseConfiguration config = new BaseConfiguration();
@@ -243,6 +243,63 @@
         assertTrue(keys.isEmpty());
     }
 
+    @Test
+    public void testPrefixDelimiter(){
+        final BaseConfiguration config = new BaseConfiguration();
+        config.setProperty("part1.part2@test.key1", "value1");
+        config.setProperty("part1.part2", "value2");
+        config.setProperty("part3.part4@testing.key2", "value3");
+
+        final SubsetConfiguration subset = new SubsetConfiguration(config, "part1.part2", "@");
+        // Check subset properties
+        assertEquals("value1", subset.getString("test.key1"));
+        assertEquals("value2", subset.getString(""));
+        assertNull(subset.getString("testing.key2"));
+
+        // Check for empty subset configuration and iterator
+        assertEquals(2, subset.size());
+        assertFalse(subset.isEmpty());
+        assertTrue(subset.getKeys().hasNext());
+    }
+
+    @Test
+    public void testPrefixDelimiterNegativeTest(){
+        final BaseConfiguration config = new BaseConfiguration();
+        config.setProperty("part1.part2@test.key1", "value1");
+        config.setProperty("part3.part4@testing.key2", "value2");
+
+        final SubsetConfiguration subset = new SubsetConfiguration(config, "part1.part2", "@") {
+            // Anonymous inner class declaration to override SubsetConfiguration.getKeysInternal() - Call
+            // ImutableConfiguration.getKeys(String) on the parent configuration of the SubsetConfiguration in order to
+            // not consequently pass the prefix delimiter
+            @Override
+            protected Iterator<String> getKeysInternal() {
+                Class<?> subsetIteratorClass;
+                try {
+                    subsetIteratorClass = Class
+                            .forName("org.apache.commons.configuration2.SubsetConfiguration$SubsetIterator");
+                    final Constructor<?> ctor = subsetIteratorClass.getDeclaredConstructor(SubsetConfiguration.class,
+                            Iterator.class);
+                    ctor.setAccessible(true);
+
+                    return (Iterator<String>) ctor.newInstance(this, parent.getKeys("part1.part2"));
+                } catch (final Exception ex) {
+                    throw new IllegalArgumentException(ex);
+                }
+            }
+        };
+
+        // Check subset properties - contains one property
+        assertEquals("value1", subset.getString("test.key1"));
+        assertNull(subset.getString("testing.key2"));
+
+        // Check for empty subset configuration and iterator - even if the SubsetConfiguration contains properties, like
+        // checked previously its states that it is empty
+        assertEquals(0, subset.size());
+        assertTrue(subset.isEmpty());
+        assertFalse(subset.getKeys().hasNext());
+    }
+
     /**
      * Tests whether the list delimiter handler is also set for the parent configuration.
      */
@@ -308,61 +365,4 @@
         subset.setThrowExceptionOnMissing(true);
         assertThrows(NoSuchElementException.class, () -> config.getString("foo"));
     }
-
-    @Test
-    public void testPrefixDelimiter(){
-        final BaseConfiguration config = new BaseConfiguration();
-        config.setProperty("part1.part2@test.key1", "value1");
-        config.setProperty("part1.part2", "value2");
-        config.setProperty("part3.part4@testing.key2", "value3");
-
-        final SubsetConfiguration subset = new SubsetConfiguration(config, "part1.part2", "@");
-        // Check subset properties
-        assertEquals("value1", subset.getString("test.key1"));
-        assertEquals("value2", subset.getString(""));
-        assertNull(subset.getString("testing.key2"));
-
-        // Check for empty subset configuration and iterator
-        assertEquals(2, subset.size());
-        assertFalse(subset.isEmpty());
-        assertTrue(subset.getKeys().hasNext());
-    }
-
-    @Test
-    public void testPrefixDelimiterNegativeTest(){
-        final BaseConfiguration config = new BaseConfiguration();
-        config.setProperty("part1.part2@test.key1", "value1");
-        config.setProperty("part3.part4@testing.key2", "value2");
-
-        final SubsetConfiguration subset = new SubsetConfiguration(config, "part1.part2", "@") {
-            // Anonymous inner class declaration to override SubsetConfiguration.getKeysInternal() - Call
-            // ImutableConfiguration.getKeys(String) on the parent configuration of the SubsetConfiguration in order to
-            // not consequently pass the prefix delimiter
-            @Override
-            protected Iterator<String> getKeysInternal() {
-                Class<?> subsetIteratorClass;
-                try {
-                    subsetIteratorClass = Class
-                            .forName("org.apache.commons.configuration2.SubsetConfiguration$SubsetIterator");
-                    final Constructor<?> ctor = subsetIteratorClass.getDeclaredConstructor(SubsetConfiguration.class,
-                            Iterator.class);
-                    ctor.setAccessible(true);
-
-                    return (Iterator<String>) ctor.newInstance(this, parent.getKeys("part1.part2"));
-                } catch (final Exception ex) {
-                    throw new IllegalArgumentException(ex);
-                }
-            }
-        };
-
-        // Check subset properties - contains one property
-        assertEquals("value1", subset.getString("test.key1"));
-        assertNull(subset.getString("testing.key2"));
-
-        // Check for empty subset configuration and iterator - even if the SubsetConfiguration contains properties, like
-        // checked previously its states that it is empty
-        assertEquals(0, subset.size());
-        assertTrue(subset.isEmpty());
-        assertFalse(subset.getKeys().hasNext());
-    }
 }
diff --git a/src/test/java/org/apache/commons/configuration2/TestXMLPropertiesConfiguration.java b/src/test/java/org/apache/commons/configuration2/TestXMLPropertiesConfiguration.java
index 4cbeed0..373ca9f 100644
--- a/src/test/java/org/apache/commons/configuration2/TestXMLPropertiesConfiguration.java
+++ b/src/test/java/org/apache/commons/configuration2/TestXMLPropertiesConfiguration.java
@@ -20,6 +20,7 @@
 import static org.apache.commons.configuration2.TempDirUtils.newFile;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.io.File;
 import java.net.URL;
@@ -66,6 +67,9 @@
 
     @Test
     public void testDOMLoad() throws Exception {
+        // Edge case
+        assertThrows(NullPointerException.class, () -> new XMLPropertiesConfiguration(null));
+        // Normal case
         final URL location = ConfigurationAssert.getTestURL(TEST_PROPERTIES_FILE);
         final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
         final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();