This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git


The following commit(s) were added to refs/heads/master by this push:
     new 01bae76  Add ImmutableConfiguration.getDuration() methods.
01bae76 is described below

commit 01bae769673fbe8a2cbbf0591f4b455f7ca76d7b
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Wed Aug 25 14:35:30 2021 -0400

    Add ImmutableConfiguration.getDuration() methods.
---
 src/changes/changes.xml                            |   3 +
 .../configuration2/AbstractConfiguration.java      |  11 +
 .../configuration2/ImmutableConfiguration.java     |  35 ++
 .../configuration2/convert/PropertyConverter.java  |  30 +-
 .../configuration2/TestBaseConfiguration.java      |  24 ++
 .../TestDefaultImmutableConfiguration.java         | 369 +++++++++++++++++++++
 6 files changed, 470 insertions(+), 2 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 239be52..707f719 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -75,6 +75,9 @@
        <action type="add" dev="ggregory" issue="CONFIGURATION-789" 
due-to="Gary Gregory">
          Add ImmutableConfiguration.getEnum() methods.
        </action>
+       <action type="add" dev="ggregory" issue="CONFIGURATION-789" 
due-to="Gary Gregory">
+         Add ImmutableConfiguration.getDuration() methods.
+       </action>       
        <!-- UPDATES -->
        <action type="update" dev="ggregory" issue="CONFIGURATION-787" 
due-to="Gary Gregory">
          Update from Apache Commons Lang 3.9 to 3.12.0.
diff --git 
a/src/main/java/org/apache/commons/configuration2/AbstractConfiguration.java 
b/src/main/java/org/apache/commons/configuration2/AbstractConfiguration.java
index 3c0e526..3cde89c 100644
--- a/src/main/java/org/apache/commons/configuration2/AbstractConfiguration.java
+++ b/src/main/java/org/apache/commons/configuration2/AbstractConfiguration.java
@@ -19,6 +19,7 @@ package org.apache.commons.configuration2;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -987,6 +988,16 @@ public abstract class AbstractConfiguration extends 
BaseEventSource implements C
     }
 
     @Override
+    public Duration getDuration(final String key) {
+        return checkNonNullValue(key, convert(Duration.class, key, null, 
true));
+    }
+
+    @Override
+    public Duration getDuration(final String key, final Duration defaultValue) 
{
+        return convert(Duration.class, key, defaultValue, false);
+    }
+
+    @Override
     public float getFloat(final String key) {
         final Float f = convert(Float.class, key, null, true);
         return checkNonNullValue(key, f).floatValue();
diff --git 
a/src/main/java/org/apache/commons/configuration2/ImmutableConfiguration.java 
b/src/main/java/org/apache/commons/configuration2/ImmutableConfiguration.java
index 1ba0052..96da9a1 100644
--- 
a/src/main/java/org/apache/commons/configuration2/ImmutableConfiguration.java
+++ 
b/src/main/java/org/apache/commons/configuration2/ImmutableConfiguration.java
@@ -18,11 +18,14 @@ package org.apache.commons.configuration2;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.Duration;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Properties;
 
+import org.apache.commons.configuration2.convert.PropertyConverter;
 import org.apache.commons.configuration2.ex.ConversionException;
 
 /**
@@ -309,6 +312,38 @@ public interface ImmutableConfiguration {
     Double getDouble(String key, Double defaultValue);
 
     /**
+     * Gets a {@link Duration} associated with the given configuration key.
+     *
+     * @param key The configuration key.
+     * @return The associated Duration if key is found and has valid format, 
default value otherwise.
+     * @throws org.apache.commons.configuration2.ex.ConversionException is 
thrown if the key maps to an object that is not a
+     *         Duration.
+     * @since 2.8.0
+     */
+    default Duration getDuration(final String key) {
+        final String string = getString(key);
+        if (string == null) {
+            throw new NoSuchElementException(key);
+        }
+        return PropertyConverter.toDuration(string);
+    }
+
+    /**
+     * Gets a {@link Duration} associated with the given configuration key.
+     *
+     * @param key The configuration key.
+     * @param defaultValue The default value.
+     * @return The associated Duration if key is found and has valid format, 
default value otherwise.
+     * @throws org.apache.commons.configuration2.ex.ConversionException is 
thrown if the key maps to an object that is not a
+     *         Duration.
+     * @since 2.8.0
+     */
+    default Duration getDuration(final String key, final Duration 
defaultValue) {
+        Object value = getProperty(key);
+        return value == null ? defaultValue : 
PropertyConverter.toDuration(value);
+    }
+
+    /**
      * Gets the value of a string property that is stored in encoded form in 
this configuration using a default
      * {@code ConfigurationDecoder}. This method works like the method with 
the same name, but it uses a default
      * {@code ConfigurationDecoder} associated with this configuration. It 
depends on a specific implementation how this
diff --git 
a/src/main/java/org/apache/commons/configuration2/convert/PropertyConverter.java
 
b/src/main/java/org/apache/commons/configuration2/convert/PropertyConverter.java
index b3e53c2..b018193 100644
--- 
a/src/main/java/org/apache/commons/configuration2/convert/PropertyConverter.java
+++ 
b/src/main/java/org/apache/commons/configuration2/convert/PropertyConverter.java
@@ -33,6 +33,8 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.Duration;
+import java.time.format.DateTimeParseException;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -46,9 +48,9 @@ import org.apache.commons.lang3.StringUtils;
 /**
  * A utility class to convert the configuration properties into any type.
  *
- * @since 1.1
+ * @since 2.8.0
  */
-final class PropertyConverter {
+public final class PropertyConverter {
 
     /** Constant for the prefix of hex numbers. */
     private static final String HEX_PREFIX = "0x";
@@ -150,6 +152,8 @@ final class PropertyConverter {
             return toInternetAddress(value);
         } else if (InetAddress.class.isAssignableFrom(cls)) {
             return toInetAddress(value);
+        } else if (Duration.class.equals(cls)) {
+            return toDuration(value);
         }
 
         throw new ConversionException("The value '" + value + "' (" + 
value.getClass() + ")" + " can't be converted to a " + cls.getName() + " 
object");
@@ -286,6 +290,28 @@ final class PropertyConverter {
     }
 
     /**
+     * Convert the specified object into a Duration.
+     *
+     * @param value the value to convert
+     * @return the converted value
+     * @throws ConversionException thrown if the value cannot be converted to 
a Duration
+     * @since 2.8.0
+     */
+    public static Duration toDuration(final Object value) throws 
ConversionException {
+        if (value instanceof Duration) {
+            return (Duration) value;
+        }
+        if (value instanceof CharSequence) {
+            try {
+                return Duration.parse((CharSequence) value);
+            } catch (DateTimeParseException e) {
+                throw new ConversionException("Could not convert " + value + " 
to Duration", e);
+            }
+        }
+        throw new ConversionException("The value " + value + " can't be 
converted to a Duration");
+    }
+
+    /**
      * Convert the specified object into a BigInteger.
      *
      * @param value the value to convert
diff --git 
a/src/test/java/org/apache/commons/configuration2/TestBaseConfiguration.java 
b/src/test/java/org/apache/commons/configuration2/TestBaseConfiguration.java
index 8e98d25..12eb7c0 100644
--- a/src/test/java/org/apache/commons/configuration2/TestBaseConfiguration.java
+++ b/src/test/java/org/apache/commons/configuration2/TestBaseConfiguration.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -308,6 +309,29 @@ public class TestBaseConfiguration {
     }
 
     @Test
+    public void testGetDuration() {
+        final Duration d = Duration.ofSeconds(1);
+        config.setProperty("durationD", d.toString());
+        final Duration oneD = Duration.ofSeconds(1);
+        final Duration twoD = Duration.ofSeconds(2);
+        assertEquals("This returns 1(Duration)", oneD, 
config.getDuration("durationD"));
+        assertEquals("This returns 1(Duration)", oneD, 
config.getDuration("durationD", twoD));
+        assertEquals("This returns 2(default Duration)", twoD, 
config.getDuration("numberNotInConfig", twoD));
+        assertEquals("This returns 1(Duration)", oneD, 
config.getDuration("durationD", twoD));
+    }
+
+    @Test(expected = ConversionException.class)
+    public void testGetDurationIncompatibleType() {
+        config.setProperty("test.empty", "");
+        config.getDuration("test.empty");
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testGetDurationUnknown() {
+        config.getDuration("numberNotInConfig");
+    }
+
+    @Test
     public void testGetEnum() {
         config.setProperty("testEnum", EnumFixture.SMALLTALK.name());
         config.setProperty("testBadEnum", "This is not an enum value.");
diff --git 
a/src/test/java/org/apache/commons/configuration2/TestDefaultImmutableConfiguration.java
 
b/src/test/java/org/apache/commons/configuration2/TestDefaultImmutableConfiguration.java
new file mode 100644
index 0000000..d0b97f3
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/configuration2/TestDefaultImmutableConfiguration.java
@@ -0,0 +1,369 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.configuration2;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Properties;
+
+import org.apache.commons.configuration2.ex.ConversionException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests {@link ImmutableConfiguration} default methods.
+ */
+public class TestDefaultImmutableConfiguration {
+
+    /** Tests default methods. This class MUST NOT override the default 
methods! */
+    private class MapImmutableConfiguration implements ImmutableConfiguration {
+
+        Map<String, Object> map = new HashMap<>();
+
+        @Override
+        public boolean containsKey(final String key) {
+            // Super is not a default method.
+            return false;
+        }
+
+        @Override
+        public <T> T get(final Class<T> cls, final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public <T> T get(final Class<T> cls, final String key, final T 
defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public Object getArray(final Class<?> cls, final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public Object getArray(final Class<?> cls, final String key, final 
Object defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public BigDecimal getBigDecimal(final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public BigDecimal getBigDecimal(final String key, final BigDecimal 
defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public BigInteger getBigInteger(final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public BigInteger getBigInteger(final String key, final BigInteger 
defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public boolean getBoolean(final String key) {
+            // Super is not a default method.
+            return false;
+        }
+
+        @Override
+        public boolean getBoolean(final String key, final boolean 
defaultValue) {
+            // Super is not a default method.
+            return false;
+        }
+
+        @Override
+        public Boolean getBoolean(final String key, final Boolean 
defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public byte getByte(final String key) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public byte getByte(final String key, final byte defaultValue) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public Byte getByte(final String key, final Byte defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public <T> Collection<T> getCollection(final Class<T> cls, final 
String key, final Collection<T> target) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public <T> Collection<T> getCollection(final Class<T> cls, final 
String key, final Collection<T> target, final Collection<T> defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public double getDouble(final String key) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public double getDouble(final String key, final double defaultValue) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public Double getDouble(final String key, final Double defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public String getEncodedString(final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public String getEncodedString(final String key, final 
ConfigurationDecoder decoder) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public float getFloat(final String key) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public float getFloat(final String key, final float defaultValue) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public Float getFloat(final String key, final Float defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public int getInt(final String key) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public int getInt(final String key, final int defaultValue) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public Integer getInteger(final String key, final Integer 
defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public Iterator<String> getKeys() {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public Iterator<String> getKeys(final String prefix) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public <T> List<T> getList(final Class<T> cls, final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public <T> List<T> getList(final Class<T> cls, final String key, final 
List<T> defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public List<Object> getList(final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public List<Object> getList(final String key, final List<?> 
defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public long getLong(final String key) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public long getLong(final String key, final long defaultValue) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public Long getLong(final String key, final Long defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public Properties getProperties(final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public Object getProperty(final String key) {
+            // Super is not a default method.
+            return map.get(key);
+        }
+
+        @Override
+        public short getShort(final String key) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public short getShort(final String key, final short defaultValue) {
+            // Super is not a default method.
+            return 0;
+        }
+
+        @Override
+        public Short getShort(final String key, final Short defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public String getString(final String key) {
+            return Objects.toString(map.get(key), null);
+        }
+
+        @Override
+        public String getString(final String key, final String defaultValue) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public String[] getStringArray(final String key) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public ImmutableConfiguration immutableSubset(final String prefix) {
+            // Super is not a default method.
+            return null;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            // Super is not a default method.
+            return false;
+        }
+
+        @Override
+        public int size() {
+            // Super is not a default method.
+            return 0;
+        }
+
+    }
+
+    private final MapImmutableConfiguration config = new 
MapImmutableConfiguration();
+
+    @Before
+    @After
+    public void clearMap() {
+        config.map.clear();
+    }
+
+    @Test
+    public void testGetDuration() {
+        final Duration d = Duration.ofSeconds(1);
+        config.map.put("durationD", d.toString());
+        final Duration oneD = Duration.ofSeconds(1);
+        final Duration twoD = Duration.ofSeconds(2);
+        assertEquals("This returns 1(Duration)", oneD, 
config.getDuration("durationD"));
+        assertEquals("This returns 1(Duration)", oneD, 
config.getDuration("durationD", twoD));
+        assertEquals("This returns 2(default Duration)", twoD, 
config.getDuration("numberNotInConfig", twoD));
+        assertEquals("This returns 1(Duration)", oneD, 
config.getDuration("durationD", twoD));
+    }
+
+    @Test(expected = ConversionException.class)
+    public void testGetDurationIncompatibleType() {
+        config.map.put("test.empty", "");
+        config.getDuration("test.empty");
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testGetDurationUnknown() {
+        config.getDuration("numberNotInConfig");
+    }
+
+}

Reply via email to