Change ConfigBeanFactory to use ConfigMemorySize and java.time.Duration

This commit is contained in:
Havoc Pennington 2015-02-26 12:40:43 -05:00
parent f1f198595a
commit 69f7b48130
8 changed files with 121 additions and 194 deletions

View File

@ -1,8 +1,5 @@
package com.typesafe.config;
import com.typesafe.config.impl.DurationUnit;
import com.typesafe.config.impl.MemoryUnit;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
@ -12,6 +9,7 @@ import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.time.Duration;
/**
* Factory for automatic creation of config classes populated with values from config.
@ -97,15 +95,13 @@ public class ConfigBeanFactory {
} else if (parameterClass == Double.class || parameterClass == double.class) {
return config.getDouble(configPropName);
} else if (parameterClass == Long.class || parameterClass == long.class) {
String rawVal = config.getString(configPropName);
if (DurationUnit.containsDurationToken(rawVal)) {
return config.getDuration(configPropName, TimeUnit.NANOSECONDS);
} else if (MemoryUnit.containsMemoryToken(rawVal)) {
return config.getBytes(configPropName);
}
return config.getLong(configPropName);
} else if (parameterClass == String.class) {
return config.getString(configPropName);
} else if (parameterClass == Duration.class) {
return config.getDuration(configPropName);
} else if (parameterClass == ConfigMemorySize.class) {
return config.getMemorySize(configPropName);
}
return config.getAnyRef(configPropName);

View File

@ -1,58 +0,0 @@
package com.typesafe.config.impl;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* https://github.com/typesafehub/config/blob/master/HOCON.md#duration-format
*/
public enum DurationUnit {
NANOSECONDS(TimeUnit.NANOSECONDS, Arrays.asList("ns", "nano", "nanos", "nanosecond", "nanoseconds")),
MICROSECONDS(TimeUnit.MICROSECONDS, Arrays.asList("us", "micro", "micros", "microsecond", "microseconds")),
MILLISECONDS(TimeUnit.MILLISECONDS,Arrays.asList("ms", "milli", "millis", "millisecond", "milliseconds")),
SECONDS(TimeUnit.SECONDS,Arrays.asList("s", "second", "seconds")),
MINUTES(TimeUnit.MINUTES,Arrays.asList("m", "minute", "minutes")),
HOURS(TimeUnit.HOURS,Arrays.asList("h", "hour", "hours")),
DAYS(TimeUnit.DAYS,Arrays.asList("d", "day", "days"));
private List<String> aliases;
private TimeUnit timeUnit;
DurationUnit(TimeUnit timeUnit,List<String> aliases) {
this.timeUnit = timeUnit;
this.aliases = aliases;
}
/**
* Finds corresponding duration unit by its string representation.
* @param rawVal - string duration value ('s','ns' etc.)
* @return one of enum values or null if none applicable
*/
public static final DurationUnit fromString(String rawVal) {
for (DurationUnit durationUnit : DurationUnit.values()) {
// note that this is deliberately case-sensitive
if(durationUnit.aliases.contains(rawVal)) {
return durationUnit;
}
}
return null;
}
/**
* Checks whether given string contains duration token.
* @param rawVal - string like '10s','45nanos' etc.
* String is case sensitive, i.e. '10S' is not treated as valid duration string
* @return true - if string contains one of enum aliases, false otherwise
*/
public static boolean containsDurationToken(String rawVal) {
String unitStr = rawVal.replaceAll("[^A-Za-z]","");
return fromString(unitStr) != null;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
}

View File

@ -1,95 +0,0 @@
package com.typesafe.config.impl;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
/**
* https://github.com/typesafehub/config/blob/master/HOCON.md#size-in-bytes-format
*/
public enum MemoryUnit {
BYTES("", 1024, 0),
KILOBYTES("kilo", 1000, 1),
MEGABYTES("mega", 1000, 2),
GIGABYTES("giga", 1000, 3),
TERABYTES("tera", 1000, 4),
PETABYTES("peta", 1000, 5),
EXABYTES("exa", 1000, 6),
ZETTABYTES("zetta", 1000, 7),
YOTTABYTES("yotta", 1000, 8),
KIBIBYTES("kibi", 1024, 1),
MEBIBYTES("mebi", 1024, 2),
GIBIBYTES("gibi", 1024, 3),
TEBIBYTES("tebi", 1024, 4),
PEBIBYTES("pebi", 1024, 5),
EXBIBYTES("exbi", 1024, 6),
ZEBIBYTES("zebi", 1024, 7),
YOBIBYTES("yobi", 1024, 8);
final String prefix;
final int powerOf;
final int power;
final BigInteger bytes;
MemoryUnit(String prefix, int powerOf, int power) {
this.prefix = prefix;
this.powerOf = powerOf;
this.power = power;
this.bytes = BigInteger.valueOf(powerOf).pow(power);
}
private static Map<String, MemoryUnit> makeUnitsMap() {
Map<String, MemoryUnit> map = new HashMap<String, MemoryUnit>();
for (MemoryUnit unit : MemoryUnit.values()) {
map.put(unit.prefix + "byte", unit);
map.put(unit.prefix + "bytes", unit);
if (unit.prefix.length() == 0) {
map.put("b", unit);
map.put("B", unit);
map.put("", unit); // no unit specified means bytes
} else {
String first = unit.prefix.substring(0, 1);
String firstUpper = first.toUpperCase();
if (unit.powerOf == 1024) {
map.put(first, unit); // 512m
map.put(firstUpper, unit); // 512M
map.put(firstUpper + "i", unit); // 512Mi
map.put(firstUpper + "iB", unit); // 512MiB
} else if (unit.powerOf == 1000) {
if (unit.power == 1) {
map.put(first + "B", unit); // 512kB
} else {
map.put(firstUpper + "B", unit); // 512MB
}
} else {
throw new RuntimeException("broken MemoryUnit enum");
}
}
}
return map;
}
private static Map<String, MemoryUnit> unitsMap = makeUnitsMap();
static MemoryUnit parseUnit(String unit) {
return unitsMap.get(unit);
}
/**
* Checks whether given string contains memory token.
* @param rawVal - string like '10B','45bytes' etc.
* String is case sensitive, i.e. '10KILOS' is not treated as valid memory size string
* @return true - if string contains memory data, false otherwise
*/
public static boolean containsMemoryToken(String rawVal) {
String unitStr = rawVal.replaceAll("[^A-Za-z]","");
for (String unit : unitsMap.keySet()) {
if(unit.equals(unitStr)) {
return true;
}
}
return false;
}
}

View File

@ -547,17 +547,27 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
if (unitString.length() > 2 && !unitString.endsWith("s"))
unitString = unitString + "s";
if(unitString.equals("")) {
// note that this is deliberately case-sensitive
if (unitString.equals("") || unitString.equals("ms") || unitString.equals("millis")
|| unitString.equals("milliseconds")) {
units = TimeUnit.MILLISECONDS;
} else if (unitString.equals("us") || unitString.equals("micros") || unitString.equals("microseconds")) {
units = TimeUnit.MICROSECONDS;
} else if (unitString.equals("ns") || unitString.equals("nanos") || unitString.equals("nanoseconds")) {
units = TimeUnit.NANOSECONDS;
} else if (unitString.equals("d") || unitString.equals("days")) {
units = TimeUnit.DAYS;
} else if (unitString.equals("h") || unitString.equals("hours")) {
units = TimeUnit.HOURS;
} else if (unitString.equals("s") || unitString.equals("seconds")) {
units = TimeUnit.SECONDS;
} else if (unitString.equals("m") || unitString.equals("minutes")) {
units = TimeUnit.MINUTES;
} else {
DurationUnit durationUnit = DurationUnit.fromString(unitString);
units = durationUnit != null ? durationUnit.getTimeUnit() : null;
if(units == null) {
throw new ConfigException.BadValue(originForException,
throw new ConfigException.BadValue(originForException,
pathForException, "Could not parse time unit '"
+ originalUnitString
+ "' (try ns, us, ms, s, m, h, d)");
}
}
try {
@ -577,6 +587,77 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
}
}
private static enum MemoryUnit {
BYTES("", 1024, 0),
KILOBYTES("kilo", 1000, 1),
MEGABYTES("mega", 1000, 2),
GIGABYTES("giga", 1000, 3),
TERABYTES("tera", 1000, 4),
PETABYTES("peta", 1000, 5),
EXABYTES("exa", 1000, 6),
ZETTABYTES("zetta", 1000, 7),
YOTTABYTES("yotta", 1000, 8),
KIBIBYTES("kibi", 1024, 1),
MEBIBYTES("mebi", 1024, 2),
GIBIBYTES("gibi", 1024, 3),
TEBIBYTES("tebi", 1024, 4),
PEBIBYTES("pebi", 1024, 5),
EXBIBYTES("exbi", 1024, 6),
ZEBIBYTES("zebi", 1024, 7),
YOBIBYTES("yobi", 1024, 8);
final String prefix;
final int powerOf;
final int power;
final BigInteger bytes;
MemoryUnit(String prefix, int powerOf, int power) {
this.prefix = prefix;
this.powerOf = powerOf;
this.power = power;
this.bytes = BigInteger.valueOf(powerOf).pow(power);
}
private static Map<String, MemoryUnit> makeUnitsMap() {
Map<String, MemoryUnit> map = new HashMap<String, MemoryUnit>();
for (MemoryUnit unit : MemoryUnit.values()) {
map.put(unit.prefix + "byte", unit);
map.put(unit.prefix + "bytes", unit);
if (unit.prefix.length() == 0) {
map.put("b", unit);
map.put("B", unit);
map.put("", unit); // no unit specified means bytes
} else {
String first = unit.prefix.substring(0, 1);
String firstUpper = first.toUpperCase();
if (unit.powerOf == 1024) {
map.put(first, unit); // 512m
map.put(firstUpper, unit); // 512M
map.put(firstUpper + "i", unit); // 512Mi
map.put(firstUpper + "iB", unit); // 512MiB
} else if (unit.powerOf == 1000) {
if (unit.power == 1) {
map.put(first + "B", unit); // 512kB
} else {
map.put(firstUpper + "B", unit); // 512MB
}
} else {
throw new RuntimeException("broken MemoryUnit enum");
}
}
}
return map;
}
private static Map<String, MemoryUnit> unitsMap = makeUnitsMap();
static MemoryUnit parseUnit(String unit) {
return unitsMap.get(unit);
}
}
/**
* Parses a size-in-bytes string. If no units are specified in the string,
* it is assumed to be in bytes. The returned value is in bytes. The purpose

View File

@ -1,32 +1,34 @@
package beanconfig;
import com.typesafe.config.ConfigMemorySize;
public class BytesConfig {
private Long kilobyte;
private Long kibibyte;
private Long thousandBytes;
private ConfigMemorySize kilobyte;
private ConfigMemorySize kibibyte;
private ConfigMemorySize thousandBytes;
public Long getKilobyte() {
public ConfigMemorySize getKilobyte() {
return kilobyte;
}
public void setKilobyte(Long kilobyte) {
public void setKilobyte(ConfigMemorySize kilobyte) {
this.kilobyte = kilobyte;
}
public Long getKibibyte() {
public ConfigMemorySize getKibibyte() {
return kibibyte;
}
public void setKibibyte(Long kibibyte) {
public void setKibibyte(ConfigMemorySize kibibyte) {
this.kibibyte = kibibyte;
}
public Long getThousandBytes() {
public ConfigMemorySize getThousandBytes() {
return thousandBytes;
}
public void setThousandBytes(Long thousandBytes) {
public void setThousandBytes(ConfigMemorySize thousandBytes) {
this.thousandBytes = thousandBytes;
}
}

View File

@ -1,33 +1,34 @@
package beanconfig;
import java.time.Duration;
public class DurationsConfig {
Long second;
Long secondAsNumber;
Long halfSecond;
Duration second;
Duration secondAsNumber;
Duration halfSecond;
public Long getSecond() {
public Duration getSecond() {
return second;
}
public void setSecond(Long second) {
public void setSecond(Duration second) {
this.second = second;
}
public Long getSecondAsNumber() {
public Duration getSecondAsNumber() {
return secondAsNumber;
}
public void setSecondAsNumber(Long secondAsNumber) {
public void setSecondAsNumber(Duration secondAsNumber) {
this.secondAsNumber = secondAsNumber;
}
public Long getHalfSecond() {
public Duration getHalfSecond() {
return halfSecond;
}
public void setHalfSecond(Long halfSecond) {
public void setHalfSecond(Duration halfSecond) {
this.halfSecond = halfSecond;
}
}

View File

@ -55,7 +55,7 @@
},
"durations" : {
"second" : 1s,
"secondAsNumber" : 1000000000,
"secondAsNumber" : 1000,
"halfSecond" : 0.5s
},

View File

@ -4,7 +4,7 @@
package com.typesafe.config
import java.io.{ InputStream, InputStreamReader }
import java.util.concurrent.TimeUnit
import java.time.Duration;
import beanconfig._
import org.junit.Assert._
@ -70,18 +70,18 @@ class ConfigBeanFactoryTest {
def testCreateDuration() {
val beanConfig: DurationsConfig = ConfigBeanFactory.create(loadConfig().getConfig("durations"), classOf[DurationsConfig])
assertNotNull(beanConfig)
assertEquals(beanConfig.getHalfSecond, TimeUnit.MILLISECONDS.toNanos(500))
assertEquals(beanConfig.getSecond, TimeUnit.SECONDS.toNanos(1))
assertEquals(beanConfig.getSecondAsNumber, TimeUnit.SECONDS.toNanos(1))
assertEquals(beanConfig.getHalfSecond, Duration.ofMillis(500))
assertEquals(beanConfig.getSecond, Duration.ofMillis(1000))
assertEquals(beanConfig.getSecondAsNumber, Duration.ofMillis(1000))
}
@Test
def testCreateBytes() {
val beanConfig: BytesConfig = ConfigBeanFactory.create(loadConfig().getConfig("bytes"), classOf[BytesConfig])
assertNotNull(beanConfig)
assertEquals(beanConfig.getKibibyte, 1024L)
assertEquals(beanConfig.getKilobyte, 1000L)
assertEquals(beanConfig.getThousandBytes, 1000L)
assertEquals(beanConfig.getKibibyte, ConfigMemorySize.ofBytes(1024))
assertEquals(beanConfig.getKilobyte, ConfigMemorySize.ofBytes(1000))
assertEquals(beanConfig.getThousandBytes, ConfigMemorySize.ofBytes(1000))
}
private def loadConfig(): Config = {