From dddcd0443a5deb293c72187a8b4e9dcf4defd710 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 25 Feb 2015 21:21:08 -0500 Subject: [PATCH] Support java.time.Duration getters on Config Also support fromAnyRef on a Duration --- .../main/java/com/typesafe/config/Config.java | 34 +++++++++++++++++++ .../com/typesafe/config/impl/ConfigImpl.java | 3 ++ .../typesafe/config/impl/SimpleConfig.java | 18 ++++++++++ .../com/typesafe/config/impl/ConfigTest.scala | 11 ++++++ .../typesafe/config/impl/PublicApiTest.scala | 7 ++++ 5 files changed, 73 insertions(+) diff --git a/config/src/main/java/com/typesafe/config/Config.java b/config/src/main/java/com/typesafe/config/Config.java index 9526fa1f..a09a55c9 100644 --- a/config/src/main/java/com/typesafe/config/Config.java +++ b/config/src/main/java/com/typesafe/config/Config.java @@ -3,6 +3,7 @@ */ package com.typesafe.config; +import java.time.Duration; import java.util.List; import java.util.Map; import java.util.Set; @@ -673,6 +674,28 @@ public interface Config extends ConfigMergeable { */ long getDuration(String path, TimeUnit unit); + /** + * Gets a value as a java.time.Duration. If the value is + * already a number, then it's taken as milliseconds; if it's + * a string, it's parsed understanding units suffixes like + * "10m" or "5ns" as documented in the the + * spec. This method never returns null. + * + * @since 1.3.0 + * + * @param path + * path expression + * @return the duration value at the requested path + * @throws ConfigException.Missing + * if value is absent or null + * @throws ConfigException.WrongType + * if value is not convertible to Long or String + * @throws ConfigException.BadValue + * if value cannot be parsed as a number of the given TimeUnit + */ + Duration getDuration(String path); + /** * Gets a list value (with any element type) as a {@link ConfigList}, which * implements {@code java.util.List}. Throws if the path is @@ -742,6 +765,17 @@ public interface Config extends ConfigMergeable { */ List getDurationList(String path, TimeUnit unit); + /** + * Gets a list, converting each value in the list to a duration, using the + * same rules as {@link #getDuration(String)}. + * + * @since 1.3.0 + * @param path + * a path expression + * @return list of durations + */ + List getDurationList(String path); + /** * Clone the config with only the given path (and its children) retained; * all sibling paths are removed. diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java index 1c9cfc85..22167731 100644 --- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java +++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java @@ -6,6 +6,7 @@ package com.typesafe.config.impl; import java.io.File; import java.lang.ref.WeakReference; import java.net.URL; +import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -241,6 +242,8 @@ public class ConfigImpl { return ConfigNumber.newNumber(origin, ((Number) object).doubleValue(), null); } + } else if (object instanceof Duration) { + return new ConfigLong(origin, ((Duration) object).toMillis(), null); } else if (object instanceof Map) { if (((Map) object).isEmpty()) return emptyObject(origin); diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java index 6b8f8f9f..421f98b2 100644 --- a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java +++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java @@ -7,6 +7,7 @@ import java.io.ObjectStreamException; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; @@ -272,6 +273,13 @@ final class SimpleConfig implements Config, MergeableValue, Serializable { return result; } + @Override + public Duration getDuration(String path) { + ConfigValue v = find(path, ConfigValueType.STRING); + long nanos = parseDuration((String) v.unwrapped(), v.origin(), path); + return Duration.ofNanos(nanos); + } + @SuppressWarnings("unchecked") private List getHomogeneousUnwrappedList(String path, ConfigValueType expected) { @@ -437,6 +445,16 @@ final class SimpleConfig implements Config, MergeableValue, Serializable { return l; } + @Override + public List getDurationList(String path) { + List l = getDurationList(path, TimeUnit.NANOSECONDS); + List builder = new ArrayList(l.size()); + for (Long value : l) { + builder.add(Duration.ofNanos(value)); + } + return builder; + } + @Deprecated @Override public List getMillisecondsList(String path) { diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala index 3d1f0017..576486d5 100644 --- a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala +++ b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala @@ -769,6 +769,17 @@ class ConfigTest extends TestUtils { conf.getNanosecondsList("durations.secondsList").asScala) assertEquals(500L, conf.getMilliseconds("durations.halfSecond")) + // get durations as java.time.Duration + assertEquals(1000L, conf.getDuration("durations.second").toMillis) + assertEquals(asNanos(1), conf.getDuration("durations.second").toNanos) + assertEquals(1000L, conf.getDuration("durations.secondAsNumber").toMillis) + assertEquals(asNanos(1), conf.getDuration("durations.secondAsNumber").toNanos) + assertEquals(Seq(1000L, 2000L, 3000L, 4000L), + conf.getDurationList("durations.secondsList").asScala.map(_.toMillis)) + assertEquals(Seq(asNanos(1), asNanos(2), asNanos(3), asNanos(4)), + conf.getDurationList("durations.secondsList").asScala.map(_.toNanos)) + assertEquals(500L, conf.getDuration("durations.halfSecond").toMillis) + def assertDurationAsTimeUnit(unit: TimeUnit): Unit = { def ms2unit(l: Long) = unit.convert(l, MILLISECONDS) def s2unit(i: Int) = unit.convert(i, SECONDS) diff --git a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala index ead13c18..8c962c56 100644 --- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala +++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala @@ -14,6 +14,7 @@ import scala.collection.mutable import equiv03.SomethingInEquiv03 import java.io.StringReader import java.net.URL +import java.time.Duration class PublicApiTest extends TestUtils { @Test @@ -175,6 +176,12 @@ class PublicApiTest extends TestUtils { testFromValue(longValue(512), ConfigMemorySize.ofBytes(512)); } + @Test + def fromDuration() { + testFromValue(longValue(1000), Duration.ofMillis(1000)); + testFromValue(longValue(1000*60*60*24), Duration.ofDays(1)); + } + @Test def roundTripUnwrap() { val conf = ConfigFactory.load("test01")