From aa75211b52d0a92dddb6973a4b8b1ea174568941 Mon Sep 17 00:00:00 2001
From: Dale Wijnand
Date: Thu, 3 Aug 2017 10:43:54 +0100
Subject: [PATCH 01/83] Migrate to sbt 0.13.16
---
build.sbt | 65 +++++++++++++++++
config/build.sbt | 2 +-
project/Build.scala | 119 --------------------------------
project/PublishToSonatype.scala | 48 +++++++++++++
project/build.properties | 2 +-
5 files changed, 115 insertions(+), 121 deletions(-)
delete mode 100644 project/Build.scala
create mode 100644 project/PublishToSonatype.scala
diff --git a/build.sbt b/build.sbt
index 65be9256f..1eba6413b 100644
--- a/build.sbt
+++ b/build.sbt
@@ -13,6 +13,58 @@ scalacOptions in GlobalScope in Test := Seq("-unchecked", "-deprecation", "-feat
scalaVersion in ThisBuild := "2.10.4"
+val sonatype = new PublishToSonatype {
+ def projectUrl = "https://github.com/typesafehub/config"
+ def developerId = "havocp"
+ def developerName = "Havoc Pennington"
+ def developerUrl = "http://ometer.com/"
+ def scmUrl = "git://github.com/typesafehub/config.git"
+}
+
+lazy val commonSettings: Seq[Setting[_]] = Def.settings(
+ unpublished,
+ javaVersionPrefix in javaVersionCheck := None
+)
+
+lazy val root = (project in file("."))
+ .settings(
+ commonSettings,
+ aggregate in doc := false,
+ doc := (doc in (configLib, Compile)).value,
+ aggregate in packageDoc := false,
+ packageDoc := (packageDoc in (configLib, Compile)).value,
+ aggregate in checkstyle := false,
+ checkstyle := (checkstyle in (configLib, Compile)).value
+ )
+ .aggregate(
+ testLib, configLib,
+ simpleLibScala, simpleAppScala, complexAppScala,
+ simpleLibJava, simpleAppJava, complexAppJava
+ )
+
+lazy val configLib = Project("config", file("config"))
+ .settings(
+ sonatype.settings,
+ osgiSettings,
+ OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl"),
+ publish := sys.error("use publishSigned instead of plain publish"),
+ publishLocal := sys.error("use publishLocalSigned instead of plain publishLocal")
+ )
+ .enablePlugins(SbtOsgi)
+ .dependsOn(testLib % "test->test")
+
+def proj(id: String, base: File) = Project(id, base) settings commonSettings
+
+lazy val testLib = proj("config-test-lib", file("test-lib"))
+
+lazy val simpleLibScala = proj("config-simple-lib-scala", file("examples/scala/simple-lib")) dependsOn configLib
+lazy val simpleAppScala = proj("config-simple-app-scala", file("examples/scala/simple-app")) dependsOn simpleLibScala
+lazy val complexAppScala = proj("config-complex-app-scala", file("examples/scala/complex-app")) dependsOn simpleLibScala
+
+lazy val simpleLibJava = proj("config-simple-lib-java", file("examples/java/simple-lib")) dependsOn configLib
+lazy val simpleAppJava = proj("config-simple-app-java", file("examples/java/simple-app")) dependsOn simpleLibJava
+lazy val complexAppJava = proj("config-complex-app-java", file("examples/java/complex-app")) dependsOn simpleLibJava
+
useGpg := true
aggregate in PgpKeys.publishSigned := false
@@ -20,3 +72,16 @@ PgpKeys.publishSigned := (PgpKeys.publishSigned in configLib).value
aggregate in PgpKeys.publishLocalSigned := false
PgpKeys.publishLocalSigned := (PgpKeys.publishLocalSigned in configLib).value
+
+val unpublished = Seq(
+ // no artifacts in this project
+ publishArtifact := false,
+ // make-pom has a more specific publishArtifact setting already
+ // so needs specific override
+ publishArtifact in makePom := false,
+ // no docs to publish
+ publishArtifact in packageDoc := false,
+ // can't seem to get rid of ivy files except by no-op'ing the entire publish task
+ publish := {},
+ publishLocal := {}
+)
diff --git a/config/build.sbt b/config/build.sbt
index 7d3fbe218..5249ee598 100644
--- a/config/build.sbt
+++ b/config/build.sbt
@@ -62,7 +62,7 @@ checkstyle in Compile := {
}
// add checkstyle as a dependency of doc
-doc in Compile <<= (doc in Compile).dependsOn(checkstyle in Compile)
+doc in Compile := ((doc in Compile).dependsOn(checkstyle in Compile)).value
findbugsSettings
findbugsReportType := Some(ReportType.Html)
diff --git a/project/Build.scala b/project/Build.scala
deleted file mode 100644
index 00d33767c..000000000
--- a/project/Build.scala
+++ /dev/null
@@ -1,119 +0,0 @@
-import sbt._
-import Keys._
-import com.etsy.sbt.checkstyle.CheckstylePlugin.autoImport._
-import com.typesafe.sbt.osgi.SbtOsgi
-import com.typesafe.sbt.osgi.SbtOsgi.autoImport._
-import com.typesafe.sbt.JavaVersionCheckPlugin.autoImport._
-
-object ConfigBuild extends Build {
- val unpublished = Seq(
- // no artifacts in this project
- publishArtifact := false,
- // make-pom has a more specific publishArtifact setting already
- // so needs specific override
- publishArtifact in makePom := false,
- // no docs to publish
- publishArtifact in packageDoc := false,
- // can't seem to get rid of ivy files except by no-op'ing the entire publish task
- publish := {},
- publishLocal := {}
- )
-
- object sonatype extends PublishToSonatype {
- def projectUrl = "https://github.com/typesafehub/config"
- def developerId = "havocp"
- def developerName = "Havoc Pennington"
- def developerUrl = "http://ometer.com/"
- def scmUrl = "git://github.com/typesafehub/config.git"
- }
-
- override val settings = super.settings ++ Seq(isSnapshot <<= isSnapshot or version(_ endsWith "-SNAPSHOT"))
-
- lazy val commonSettings: Seq[Setting[_]] = unpublished ++ Seq(javaVersionPrefix in javaVersionCheck := None)
-
- lazy val rootSettings: Seq[Setting[_]] =
- commonSettings ++
- Seq(aggregate in doc := false,
- doc := (doc in (configLib, Compile)).value,
- aggregate in packageDoc := false,
- packageDoc := (packageDoc in (configLib, Compile)).value,
- aggregate in checkstyle := false,
- checkstyle := (checkstyle in (configLib, Compile)).value)
-
- lazy val root = Project(id = "root",
- base = file("."),
- settings = rootSettings) aggregate(testLib, configLib,
- simpleLibScala, simpleAppScala, complexAppScala,
- simpleLibJava, simpleAppJava, complexAppJava)
-
- lazy val configLib = Project(id = "config",
- base = file("config"),
- settings =
- sonatype.settings ++
- osgiSettings ++
- Seq(
- OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl"),
- publish := sys.error("use publishSigned instead of plain publish"),
- publishLocal := sys.error("use publishLocalSigned instead of plain publishLocal")
- )).enablePlugins(SbtOsgi) dependsOn testLib % "test->test"
-
- def project(id: String, base: File) = Project(id, base, settings = commonSettings)
-
- lazy val testLib = project("config-test-lib", file("test-lib"))
-
- lazy val simpleLibScala = project("config-simple-lib-scala", file("examples/scala/simple-lib")) dependsOn configLib
- lazy val simpleAppScala = project("config-simple-app-scala", file("examples/scala/simple-app")) dependsOn simpleLibScala
- lazy val complexAppScala = project("config-complex-app-scala", file("examples/scala/complex-app")) dependsOn simpleLibScala
-
- lazy val simpleLibJava = project("config-simple-lib-java", file("examples/java/simple-lib")) dependsOn configLib
- lazy val simpleAppJava = project("config-simple-app-java", file("examples/java/simple-app")) dependsOn simpleLibJava
- lazy val complexAppJava = project("config-complex-app-java", file("examples/java/complex-app")) dependsOn simpleLibJava
-}
-
-// from https://raw.github.com/paulp/scala-improving/master/project/PublishToSonatype.scala
-
-abstract class PublishToSonatype {
- val ossSnapshots = "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
- val ossStaging = "Sonatype OSS Staging" at "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
-
- def projectUrl: String
- def developerId: String
- def developerName: String
- def developerUrl: String
-
- def licenseName = "Apache License, Version 2.0"
- def licenseUrl = "http://www.apache.org/licenses/LICENSE-2.0"
- def licenseDistribution = "repo"
- def scmUrl: String
- def scmConnection = "scm:git:" + scmUrl
-
- def generatePomExtra: xml.NodeSeq = {
- { projectUrl }
-
-
- { licenseName }
- { licenseUrl }
- { licenseDistribution }
-
-
-
- { scmUrl }
- { scmConnection }
-
-
-
- { developerId }
- { developerName }
- { developerUrl }
-
-
- }
-
- def settings: Seq[Setting[_]] = Seq(
- publishMavenStyle := true,
- publishTo <<= isSnapshot { (snapshot) => Some(if (snapshot) ossSnapshots else ossStaging) },
- publishArtifact in Test := false,
- pomIncludeRepository := (_ => false),
- pomExtra := generatePomExtra
- )
-}
diff --git a/project/PublishToSonatype.scala b/project/PublishToSonatype.scala
new file mode 100644
index 000000000..b6b7ca546
--- /dev/null
+++ b/project/PublishToSonatype.scala
@@ -0,0 +1,48 @@
+import sbt._, Keys._
+
+// from https://raw.github.com/paulp/scala-improving/master/project/PublishToSonatype.scala
+abstract class PublishToSonatype {
+ val ossSnapshots = "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
+ val ossStaging = "Sonatype OSS Staging" at "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
+
+ def projectUrl: String
+ def developerId: String
+ def developerName: String
+ def developerUrl: String
+
+ def licenseName = "Apache License, Version 2.0"
+ def licenseUrl = "http://www.apache.org/licenses/LICENSE-2.0"
+ def licenseDistribution = "repo"
+ def scmUrl: String
+ def scmConnection = "scm:git:" + scmUrl
+
+ def generatePomExtra: xml.NodeSeq = {
+ { projectUrl }
+
+
+ { licenseName }
+ { licenseUrl }
+ { licenseDistribution }
+
+
+
+ { scmUrl }
+ { scmConnection }
+
+
+
+ { developerId }
+ { developerName }
+ { developerUrl }
+
+
+ }
+
+ def settings: Seq[Setting[_]] = Seq(
+ publishMavenStyle := true,
+ publishTo := Some(if (isSnapshot.value) ossSnapshots else ossStaging),
+ publishArtifact in Test := false,
+ pomIncludeRepository := (_ => false),
+ pomExtra := generatePomExtra
+ )
+}
diff --git a/project/build.properties b/project/build.properties
index 43b8278c6..c091b86ca 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.13.11
+sbt.version=0.13.16
From 64e0a5e07d5b3ccd8dc4064e969499975dd1e0e8 Mon Sep 17 00:00:00 2001
From: Karthick Sankarachary
Date: Fri, 15 Sep 2017 18:13:33 -0700
Subject: [PATCH 02/83] #495 Add Support For Set Types In Config Beans
---
.../typesafe/config/impl/ConfigBeanImpl.java | 8 +
.../src/test/java/beanconfig/SetsConfig.java | 139 ++++++++++++++++++
.../resources/beanconfig/beanconfig01.conf | 26 ++++
.../config/impl/ConfigBeanFactoryTest.scala | 33 +++++
4 files changed, 206 insertions(+)
create mode 100644 config/src/test/java/beanconfig/SetsConfig.java
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
index 69da879b4..66d059ba1 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
@@ -11,9 +11,11 @@
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.time.Duration;
+import java.util.Set;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigObject;
@@ -160,6 +162,8 @@ private static Object getValue(Class> beanClass, Type parameterType, Class>
return config.getAnyRef(configPropName);
} else if (parameterClass == List.class) {
return getListValue(beanClass, parameterType, parameterClass, config, configPropName);
+ } else if (parameterClass == Set.class) {
+ return getSetValue(beanClass, parameterType, parameterClass, config, configPropName);
} else if (parameterClass == Map.class) {
// we could do better here, but right now we don't.
Type[] typeArgs = ((ParameterizedType)parameterType).getActualTypeArguments();
@@ -186,6 +190,10 @@ private static Object getValue(Class> beanClass, Type parameterType, Class>
}
}
+ private static Object getSetValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config, String configPropName) {
+ return new HashSet((List) getListValue(beanClass, parameterType, parameterClass, config, configPropName));
+ }
+
private static Object getListValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config, String configPropName) {
Type elementType = ((ParameterizedType)parameterType).getActualTypeArguments()[0];
diff --git a/config/src/test/java/beanconfig/SetsConfig.java b/config/src/test/java/beanconfig/SetsConfig.java
new file mode 100644
index 000000000..b81540df9
--- /dev/null
+++ b/config/src/test/java/beanconfig/SetsConfig.java
@@ -0,0 +1,139 @@
+package beanconfig;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigMemorySize;
+import com.typesafe.config.ConfigObject;
+import com.typesafe.config.ConfigValue;
+
+import java.time.Duration;
+import java.util.Set;
+
+public class SetsConfig {
+
+ Set empty;
+ Set ofInt;
+ Set ofString;
+ Set ofDouble;
+ Set ofLong;
+ Set
@@ -36,21 +36,21 @@
call {@link com.typesafe.config.ConfigFactory#load()}
to get the default one. Typically a library might offer two constructors, one with a Config parameter
and one which uses {@link com.typesafe.config.ConfigFactory#load()}.
- Example library code:Java and Scala.
+ Example library code:Java and Scala.
If you want to use .conf files in addition to .json and .properties,
- see the README for some short examples
- and the full HOCON spec for the long version.
+ see the README for some short examples
+ and the full HOCON spec for the long version.
diff --git a/config/src/main/java/com/typesafe/config/parser/ConfigNode.java b/config/src/main/java/com/typesafe/config/parser/ConfigNode.java
index 43ac3f51b..e9954e9a7 100644
--- a/config/src/main/java/com/typesafe/config/parser/ConfigNode.java
+++ b/config/src/main/java/com/typesafe/config/parser/ConfigNode.java
@@ -10,8 +10,8 @@
* Note: at present there is no way to obtain an instance of this interface, so
* please ignore it. A future release will make syntax tree nodes available in
* the public API. If you are interested in working on it, please see: https://github.com/typesafehub/config/issues/300
+ * href="https://github.com/lightbend/config/issues/300"
+ * >https://github.com/lightbend/config/issues/300
*
*
* Because this object is immutable, it is safe to use from multiple threads and
diff --git a/config/src/main/java/com/typesafe/config/parser/package.html b/config/src/main/java/com/typesafe/config/parser/package.html
index ef099cc4d..b0e7b3cea 100644
--- a/config/src/main/java/com/typesafe/config/parser/package.html
+++ b/config/src/main/java/com/typesafe/config/parser/package.html
@@ -14,7 +14,7 @@
the com.typesafe.config package instead. You would use the raw
parser if you're doing something like reading, modifying, and re-saving a config
file. For info on the main config API this parser is a part of,
-see the project site.
+see the project site.
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConcatenationTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConcatenationTest.scala
index aa70347e7..acf898c3f 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConcatenationTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConcatenationTest.scala
@@ -346,7 +346,7 @@ class ConcatenationTest extends TestUtils {
}
// We would ideally make this case NOT throw an exception but we need to do some work
- // to get there, see https://github.com/typesafehub/config/issues/160
+ // to get there, see https://github.com/lightbend/config/issues/160
@Test
def plusEqualsMultipleTimesNestedInArray() {
val e = intercept[ConfigException.Parse] {
@@ -357,7 +357,7 @@ class ConcatenationTest extends TestUtils {
}
// We would ideally make this case NOT throw an exception but we need to do some work
- // to get there, see https://github.com/typesafehub/config/issues/160
+ // to get there, see https://github.com/lightbend/config/issues/160
@Test
def plusEqualsMultipleTimesNestedInPlusEquals() {
val e = intercept[ConfigException.Parse] {
@@ -367,7 +367,7 @@ class ConcatenationTest extends TestUtils {
assertTrue(e.getMessage.contains("limitation"))
}
- // from https://github.com/typesafehub/config/issues/177
+ // from https://github.com/lightbend/config/issues/177
@Test
def arrayConcatenationInDoubleNestedDelayedMerge() {
val unresolved = parseConfig("""d { x = [] }, c : ${d}, c { x += 1, x += 2 }""")
@@ -375,7 +375,7 @@ class ConcatenationTest extends TestUtils {
assertEquals(Seq(1, 2), conf.getIntList("c.x").asScala)
}
- // from https://github.com/typesafehub/config/issues/177
+ // from https://github.com/lightbend/config/issues/177
@Test
def arrayConcatenationAsPartOfDelayedMerge() {
val unresolved = parseConfig(""" c { x: [], x : ${c.x}[1], x : ${c.x}[2] }""")
@@ -383,7 +383,7 @@ class ConcatenationTest extends TestUtils {
assertEquals(Seq(1, 2), conf.getIntList("c.x").asScala)
}
- // from https://github.com/typesafehub/config/issues/177
+ // from https://github.com/lightbend/config/issues/177
@Test
def arrayConcatenationInDoubleNestedDelayedMerge2() {
val unresolved = parseConfig("""d { x = [] }, c : ${d}, c { x : ${c.x}[1], x : ${c.x}[2] }""")
@@ -391,7 +391,7 @@ class ConcatenationTest extends TestUtils {
assertEquals(Seq(1, 2), conf.getIntList("c.x").asScala)
}
- // from https://github.com/typesafehub/config/issues/177
+ // from https://github.com/lightbend/config/issues/177
@Test
def arrayConcatenationInTripleNestedDelayedMerge() {
val unresolved = parseConfig("""{ r: { d.x=[] }, q: ${r}, q : { d { x = [] }, c : ${q.d}, c { x : ${q.c.x}[1], x : ${q.c.x}[2] } } }""")
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
index 50add6786..9d1a49a45 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
@@ -280,7 +280,7 @@ class ConfigValueTest extends TestUtils {
}
/**
- * Reproduces the issue #461.
+ * Reproduces the issue #461.
*
- * We use a custom de-/serializer that encodes String objects in a JDK-incompatible way. Encoding used here
- * is rather simplistic: a long indicating the length in bytes (JDK uses a variable length integer) followed
- * by the string's bytes. Running this test with the original SerializedConfigValue.readExternal()
- * implementation results in an EOFException thrown during deserialization.
- */
+ * Reproduces the issue #461.
+ *
+ * We use a custom de-/serializer that encodes String objects in a JDK-incompatible way. Encoding used here
+ * is rather simplistic: a long indicating the length in bytes (JDK uses a variable length integer) followed
+ * by the string's bytes. Running this test with the original SerializedConfigValue.readExternal()
+ * implementation results in an EOFException thrown during deserialization.
+ */
@Test
def configConfigCustomSerializable() {
val aMap = configMap("a" -> 1, "b" -> 2, "c" -> 3)
@@ -295,7 +295,7 @@ class ConfigValueTest extends TestUtils {
assertEquals(expected, actual)
}
-
+
@Test
def configListEquality() {
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
diff --git a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
index 13ccd1600..702c2930c 100644
--- a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
@@ -551,7 +551,7 @@ abstract trait TestUtils {
{ s: String => s.replace(" ", "") }, // this would break with whitespace in a key or value
{ s: String => s.replace(":", " : ") }, // could break with : in a key or value
{ s: String => s.replace(",", " , ") } // could break with , in a key or value
- )
+ )
tests flatMap { t =>
if (t.whitespaceMatters) {
Seq(t)
diff --git a/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala b/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala
index 96afa1664..ac7a8ac39 100644
--- a/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala
@@ -198,7 +198,7 @@ class TokenizerTest extends TestUtils {
"""\"\""", // file ends with a backslash
"$", // file ends with a $
"${" // file ends with a ${
- )
+ )
for (t <- invalidTests) {
val tokenized = tokenizeAsList(t)
From 2330d47e05f3c247f73690c1319a981406be110b Mon Sep 17 00:00:00 2001
From: Ash
Date: Fri, 13 Jul 2018 11:31:50 +0100
Subject: [PATCH 24/83] Minor correction to the use of config.root().render()
under "Debugging Your Configuration"
Looking at the java/scaladoc of ConfigValue.render() (https://github.com/lightbend/config/blob/master/config/src/main/java/com/typesafe/config/ConfigValue.java#L48-L50)
and then looking at the implementation of `render()` itself:
https://github.com/lightbend/config/blob/master/config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java#L364-L374
it appears that `config.root().render()` returns a string that must be printed out, logged etc. Current documentation implies that calling this method will print out the string which seems to be misleading.
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 18b617b36..715ed3b44 100644
--- a/README.md
+++ b/README.md
@@ -758,8 +758,10 @@ If you have trouble with your configuration, some useful tips.
output on stderr describing each file that is loaded.
Note: this feature is not included in the older version in
Play/Akka 2.0.
- - Use `myConfig.root().render()` to get a `Config` printed out as a
+ - Use `myConfig.root().render()` to get a `Config` as a
string with comments showing where each value came from.
+ This string can be printed out on console or logged to
+ a file etc.
### Supports Java 8 and Later
From c326c2245414f5d8116786100efc8a8a452d717f Mon Sep 17 00:00:00 2001
From: Radist
Date: Sat, 14 Jul 2018 16:41:52 +0300
Subject: [PATCH 25/83] @Optional in getters for properties without field
---
.../java/com/typesafe/config/impl/ConfigBeanImpl.java | 2 +-
config/src/test/java/beanconfig/ObjectsConfig.java | 10 ++++++++++
.../typesafe/config/impl/ConfigBeanFactoryTest.scala | 1 +
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
index 66d059ba1..2b9cf5c60 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
@@ -285,7 +285,7 @@ private static boolean hasAtLeastOneBeanProperty(Class> clazz) {
private static boolean isOptionalProperty(Class beanClass, PropertyDescriptor beanProp) {
Field field = getField(beanClass, beanProp.getName());
- return field != null && (field.getAnnotationsByType(Optional.class).length > 0);
+ return field != null ? field.getAnnotationsByType(Optional.class).length > 0 : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
}
private static Field getField(Class beanClass, String fieldName) {
diff --git a/config/src/test/java/beanconfig/ObjectsConfig.java b/config/src/test/java/beanconfig/ObjectsConfig.java
index f3009c96d..11d040f50 100644
--- a/config/src/test/java/beanconfig/ObjectsConfig.java
+++ b/config/src/test/java/beanconfig/ObjectsConfig.java
@@ -8,6 +8,7 @@ public static class ValueObject {
@Optional
private String optionalValue;
private String mandatoryValue;
+ private String Default;
public String getMandatoryValue() {
return mandatoryValue;
@@ -24,6 +25,15 @@ public String getOptionalValue() {
public void setOptionalValue(String optionalValue) {
this.optionalValue = optionalValue;
}
+
+ @Optional
+ public String getDefault() {
+ return Default;
+ }
+
+ public void setDefault(String Default) {
+ this.Default = Default;
+ }
}
private ValueObject valueObject;
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala
index 00e5a093c..bd4b47043 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala
@@ -211,6 +211,7 @@ class ConfigBeanFactoryTest extends TestUtils {
assertNotNull(beanConfig)
assertNotNull(beanConfig.getValueObject)
assertNull(beanConfig.getValueObject.getOptionalValue)
+ assertNull(beanConfig.getValueObject.getDefault)
assertEquals("notNull", beanConfig.getValueObject.getMandatoryValue)
}
From 2851e491f11f03278c7b5868052773a99288e819 Mon Sep 17 00:00:00 2001
From: The Viet Nguyen
Date: Wed, 25 Jul 2018 18:50:05 +0300
Subject: [PATCH 26/83] Add syntax from file name parser option
---
.../typesafe/config/ConfigParseOptions.java | 14 +++++++++
.../typesafe/config/impl/ConfigImplUtil.java | 20 +++++++++++++
.../com/typesafe/config/impl/Parseable.java | 17 ++---------
config/src/test/resources/test01.properties | 1 +
.../config/impl/ParseableReaderTest.scala | 30 +++++++++++++++++++
.../com/typesafe/config/impl/UtilTest.scala | 26 ++++++++++++++++
6 files changed, 94 insertions(+), 14 deletions(-)
create mode 100644 config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala
diff --git a/config/src/main/java/com/typesafe/config/ConfigParseOptions.java b/config/src/main/java/com/typesafe/config/ConfigParseOptions.java
index fcfb4d69a..9dc7a121a 100644
--- a/config/src/main/java/com/typesafe/config/ConfigParseOptions.java
+++ b/config/src/main/java/com/typesafe/config/ConfigParseOptions.java
@@ -4,6 +4,8 @@
package com.typesafe.config;
+import com.typesafe.config.impl.ConfigImplUtil;
+
/**
* A set of options related to parsing.
*
@@ -62,6 +64,18 @@ public ConfigParseOptions setSyntax(ConfigSyntax syntax) {
this.includer, this.classLoader);
}
+ /**
+ * Set the file format. If set to null, assume {@link ConfigSyntax#CONF}.
+ *
+ * @param filename
+ * a configuration file name
+ * @return options with the syntax set
+ */
+ public ConfigParseOptions setSyntaxFromFilename(String filename) {
+ ConfigSyntax syntax = ConfigImplUtil.syntaxFromExtension(filename);
+ return setSyntax(syntax);
+ }
+
/**
* Gets the current syntax option, which may be null for "any".
* @return the current syntax or null
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java b/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
index 279f5ec84..9a13ea84c 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
@@ -15,6 +15,7 @@
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigOrigin;
+import com.typesafe.config.ConfigSyntax;
/**
* Internal implementation detail, not ABI stable, do not touch.
@@ -233,4 +234,23 @@ static String toCamelCase(String originalName) {
}
return nameBuilder.toString();
}
+
+ /**
+ * Guess configuration syntax from given filename.
+ *
+ * @param filename configuration filename
+ * @return configuration syntax if a match is found. Otherwise, null.
+ */
+ public static ConfigSyntax syntaxFromExtension(String filename) {
+ if (filename == null)
+ return null;
+ if (filename.endsWith(".json"))
+ return ConfigSyntax.JSON;
+ else if (filename.endsWith(".conf"))
+ return ConfigSyntax.CONF;
+ else if (filename.endsWith(".properties"))
+ return ConfigSyntax.PROPERTIES;
+ else
+ return null;
+ }
}
diff --git a/config/src/main/java/com/typesafe/config/impl/Parseable.java b/config/src/main/java/com/typesafe/config/impl/Parseable.java
index ae54a7d42..ad5146301 100644
--- a/config/src/main/java/com/typesafe/config/impl/Parseable.java
+++ b/config/src/main/java/com/typesafe/config/impl/Parseable.java
@@ -326,17 +326,6 @@ public String toString() {
return getClass().getSimpleName();
}
- private static ConfigSyntax syntaxFromExtension(String name) {
- if (name.endsWith(".json"))
- return ConfigSyntax.JSON;
- else if (name.endsWith(".conf"))
- return ConfigSyntax.CONF;
- else if (name.endsWith(".properties"))
- return ConfigSyntax.PROPERTIES;
- else
- return null;
- }
-
private static Reader readerFromStream(InputStream input) {
return readerFromStream(input, "UTF-8");
}
@@ -574,7 +563,7 @@ protected Reader reader(ConfigParseOptions options) throws IOException {
@Override
ConfigSyntax guessSyntax() {
- return syntaxFromExtension(input.getPath());
+ return ConfigImplUtil.syntaxFromExtension(input.getPath());
}
@Override
@@ -643,7 +632,7 @@ protected Reader reader() throws IOException {
@Override
ConfigSyntax guessSyntax() {
- return syntaxFromExtension(input.getName());
+ return ConfigImplUtil.syntaxFromExtension(input.getName());
}
@Override
@@ -756,7 +745,7 @@ protected AbstractConfigObject rawParseValue(ConfigOrigin origin,
@Override
ConfigSyntax guessSyntax() {
- return syntaxFromExtension(resource);
+ return ConfigImplUtil.syntaxFromExtension(resource);
}
static String parent(String resource) {
diff --git a/config/src/test/resources/test01.properties b/config/src/test/resources/test01.properties
index 94eec4470..71de4e0be 100644
--- a/config/src/test/resources/test01.properties
+++ b/config/src/test/resources/test01.properties
@@ -2,3 +2,4 @@
fromProps.abc=abc
fromProps.one=1
fromProps.bool=true
+fromProps.specialChars=hello^^
diff --git a/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala b/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala
new file mode 100644
index 000000000..70182df54
--- /dev/null
+++ b/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala
@@ -0,0 +1,30 @@
+package com.typesafe.config.impl
+
+import java.io.InputStreamReader
+
+import com.typesafe.config.{ConfigException, ConfigFactory, ConfigParseOptions}
+import org.hamcrest.CoreMatchers.containsString
+import org.junit.Assert.{assertEquals, assertThat}
+import org.junit.Test
+
+class ParseableReaderTest extends TestUtils {
+
+ @Test
+ def parse(): Unit = {
+ val filename = "/test01.properties"
+ val configInput = new InputStreamReader(getClass.getResourceAsStream(filename))
+ val config = ConfigFactory.parseReader(configInput, ConfigParseOptions.defaults()
+ .setSyntaxFromFilename(filename))
+ assertEquals("hello^^", config.getString("fromProps.specialChars"))
+ }
+
+ @Test
+ def parseIncorrectFormat(): Unit = {
+ val filename = "/test01.properties"
+ val configInput = new InputStreamReader(getClass.getResourceAsStream(filename))
+ val e = intercept[ConfigException.Parse] {
+ ConfigFactory.parseReader(configInput)
+ }
+ assertThat(e.getMessage, containsString("Expecting end of input or a comma, got '^'"))
+ }
+}
diff --git a/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala b/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala
index cf31a7166..bccbaa476 100644
--- a/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala
@@ -3,6 +3,7 @@
*/
package com.typesafe.config.impl
+import com.typesafe.config.ConfigSyntax
import org.junit.Assert._
import org.junit._
@@ -90,4 +91,29 @@ class UtilTest extends TestUtils {
roundtripUnquoted(s)
}
}
+
+ @Test
+ def syntaxFromExtensionConf(): Unit = {
+ assertEquals(ConfigSyntax.CONF, ConfigImplUtil.syntaxFromExtension("application.conf"))
+ }
+
+ @Test
+ def syntaxFromExtensionJson(): Unit = {
+ assertEquals(ConfigSyntax.JSON, ConfigImplUtil.syntaxFromExtension("application.json"))
+ }
+
+ @Test
+ def syntaxFromExtensionProperties(): Unit = {
+ assertEquals(ConfigSyntax.PROPERTIES, ConfigImplUtil.syntaxFromExtension("application.properties"))
+ }
+
+ @Test
+ def syntaxFromExtensionUnknown(): Unit = {
+ assertNull(ConfigImplUtil.syntaxFromExtension("application.exe"))
+ }
+
+ @Test
+ def syntaxFromExtensionNull(): Unit = {
+ assertNull(ConfigImplUtil.syntaxFromExtension(null))
+ }
}
From 744073fd50c842e14fa2b9c50cd8bd226ace397c Mon Sep 17 00:00:00 2001
From: The Viet Nguyen
Date: Wed, 25 Jul 2018 19:11:50 +0300
Subject: [PATCH 27/83] Unify guess syntax decision tree
---
.../src/main/java/com/typesafe/config/impl/ConfigImplUtil.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java b/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
index 9a13ea84c..1dcc43d3d 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
@@ -244,7 +244,7 @@ static String toCamelCase(String originalName) {
public static ConfigSyntax syntaxFromExtension(String filename) {
if (filename == null)
return null;
- if (filename.endsWith(".json"))
+ else if (filename.endsWith(".json"))
return ConfigSyntax.JSON;
else if (filename.endsWith(".conf"))
return ConfigSyntax.CONF;
From 9b9d3f91e8238a55cade9259ef01d3ddd8e9a6fd Mon Sep 17 00:00:00 2001
From: Konrad `ktoso` Malawski
Date: Tue, 31 Jul 2018 15:04:41 +0900
Subject: [PATCH 28/83] #575 Remove wording about apps having reference.conf
---
README.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/README.md b/README.md
index 715ed3b44..e35c756b4 100644
--- a/README.md
+++ b/README.md
@@ -233,9 +233,6 @@ The idea is that libraries and frameworks should ship with a
`application.conf`, or if they want to create multiple
configurations in a single JVM, they could use
`ConfigFactory.load("myapp")` to load their own `myapp.conf`.
-(Applications _can_ provide a `reference.conf` also if they want,
-but you may not find it necessary to separate it from
-`application.conf`.)
Libraries and frameworks should default to `ConfigFactory.load()`
if the application does not provide a custom `Config` object. This
From 04b791b6e78a1c3452e95399884d171e38b417e1 Mon Sep 17 00:00:00 2001
From: Sean Sullivan
Date: Wed, 8 Aug 2018 00:02:02 -0700
Subject: [PATCH 29/83] sbt 1.2.1
---
project/build.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project/build.properties b/project/build.properties
index d6e35076c..5620cc502 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.1.6
+sbt.version=1.2.1
From 00c84869bf5eab5a2585123d080181f530109814 Mon Sep 17 00:00:00 2001
From: Havoc Pennington
Date: Thu, 2 Jul 2015 20:24:09 -0400
Subject: [PATCH 30/83] Reimplement ResolveMemos with a ridiculous hand-rolled
hash table
This is intended to band-aid #330 with a hash table that sucks,
but ought to be much faster to copy than the stock Java one.
The stock Java hash table rehashes everything every time, while
this hash table can often just copy an array. That said, I didn't
benchmark it or anything, it may well also be super slow.
This is more or less a troll commit to get someone to do better.
---
.../java/com/typesafe/config/impl/BadMap.java | 140 ++++++++++++++++++
.../typesafe/config/impl/ResolveMemos.java | 12 +-
2 files changed, 144 insertions(+), 8 deletions(-)
create mode 100644 config/src/main/java/com/typesafe/config/impl/BadMap.java
diff --git a/config/src/main/java/com/typesafe/config/impl/BadMap.java b/config/src/main/java/com/typesafe/config/impl/BadMap.java
new file mode 100644
index 000000000..820fb3044
--- /dev/null
+++ b/config/src/main/java/com/typesafe/config/impl/BadMap.java
@@ -0,0 +1,140 @@
+package com.typesafe.config.impl;
+
+/**
+ * A terrible Map that isn't as expensive as HashMap to copy and
+ * add one item to. Please write something real if you see this
+ * and get cranky.
+ */
+final class BadMap {
+ final static class Entry {
+ final int hash;
+ final Object key;
+ final Object value;
+ final Entry next;
+
+ Entry(int hash, Object k, Object v, Entry next) {
+ this.hash = hash;
+ this.key = k;
+ this.value = v;
+ this.next = next;
+ }
+
+ Object find(Object k) {
+ if (key.equals(k))
+ return value;
+ else if (next != null)
+ return next.find(k);
+ else
+ return null;
+ }
+ }
+
+ final int size;
+ final Entry[] entries;
+
+ private final static Entry[] emptyEntries = {};
+
+ BadMap() {
+ this(0, (Entry[]) emptyEntries);
+ }
+
+ private BadMap(int size, Entry[] entries) {
+ this.size = size;
+ this.entries = entries;
+ }
+
+ BadMap copyingPut(K k, V v) {
+ int newSize = size + 1;
+ Entry[] newEntries;
+ // The "- 1" is so we pick size 2 when newSize is 1.
+ int threshold = (newSize * 2) - 1;
+ if (threshold > (entries.length * 2)) {
+ // nextPrime doesn't always return a prime larger than
+ // we passed in, so this block may not actually change
+ // the entries size.
+ newEntries = new Entry[nextPrime(threshold)];
+ } else {
+ newEntries = new Entry[entries.length];
+ }
+
+ if (newEntries.length == entries.length)
+ System.arraycopy(entries, 0, newEntries, 0, entries.length);
+ else
+ rehash(entries, newEntries);
+
+ int hash = Math.abs(k.hashCode());
+ store(newEntries, hash, k, v);
+ return new BadMap(newSize, newEntries);
+ }
+
+ private static void store(Entry[] entries, int hash, K k, V v) {
+ int i = hash % entries.length;
+ Entry old = entries[i]; // old may be null
+ entries[i] = new Entry(hash, k, v, old);
+ }
+
+ private static void store(Entry[] entries, Entry e) {
+ int i = e.hash % entries.length;
+ Entry old = entries[i]; // old may be null
+ if (old == null && e.next == null) {
+ // share the entry since it has no "next"
+ entries[i] = e;
+ } else {
+ // bah, have to copy it
+ entries[i] = new Entry(e.hash, e.key, e.value, old);
+ }
+ }
+
+ private static void rehash(Entry[] src, Entry[] dest) {
+ for (Entry old : src) {
+ if (old != null) {
+ if (old.next == null) {
+ store(dest, old);
+ } else {
+ store(dest, old.hash, old.key, old.value);
+ store(dest, old.next);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ V get(K k) {
+ if (entries.length == 0) {
+ return null;
+ } else {
+ int hash = Math.abs(k.hashCode());
+ int i = hash % entries.length;
+ Entry e = entries[i];
+ if (e == null)
+ return null;
+ else
+ return (V) e.find(k);
+ }
+ }
+
+
+ private final static int[] primes = {
+ /* Skip some early ones that are close together */
+ 2, /* 3, */ 5, /* 7, */ 11, /* 13, */ 17, /* 19, */ 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
+ 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+ 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
+ 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
+ 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
+ 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
+ 947, 953, 967, 971, 977, 983, 991, 997, 1009,
+ /* now we start skipping some, this is arbitrary */
+ 2053, 3079, 4057, 7103
+ };
+
+ private final static int nextPrime(int i) {
+ for (int p : primes) {
+ if (p > i)
+ return p;
+ }
+ /* oh well */
+ return primes[primes.length - 1];
+ }
+}
diff --git a/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java b/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java
index cf98a900d..4fe96b3ea 100644
--- a/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java
+++ b/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java
@@ -11,14 +11,14 @@
final class ResolveMemos {
// note that we can resolve things to undefined (represented as Java null,
// rather than ConfigNull) so this map can have null values.
- final private Map memos;
+ final private BadMap memos;
- private ResolveMemos(Map memos) {
+ private ResolveMemos(BadMap memos) {
this.memos = memos;
}
ResolveMemos() {
- this(new HashMap());
+ this(new BadMap());
}
AbstractConfigValue get(MemoKey key) {
@@ -26,10 +26,6 @@ AbstractConfigValue get(MemoKey key) {
}
ResolveMemos put(MemoKey key, AbstractConfigValue value) {
- // completely inefficient, but so far nobody cares about resolve()
- // performance, we can clean it up someday...
- Map copy = new HashMap(memos);
- copy.put(key, value);
- return new ResolveMemos(copy);
+ return new ResolveMemos(memos.copyingPut(key, value));
}
}
From 9215e057a825807a6e01a569f1b44c58b5c755a9 Mon Sep 17 00:00:00 2001
From: Havoc Pennington
Date: Fri, 3 Jul 2015 09:38:47 -0400
Subject: [PATCH 31/83] minor cleanups to BadMap
---
.../main/java/com/typesafe/config/impl/BadMap.java | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/BadMap.java b/config/src/main/java/com/typesafe/config/impl/BadMap.java
index 820fb3044..0c59eba9d 100644
--- a/config/src/main/java/com/typesafe/config/impl/BadMap.java
+++ b/config/src/main/java/com/typesafe/config/impl/BadMap.java
@@ -46,13 +46,12 @@ private BadMap(int size, Entry[] entries) {
BadMap copyingPut(K k, V v) {
int newSize = size + 1;
Entry[] newEntries;
- // The "- 1" is so we pick size 2 when newSize is 1.
- int threshold = (newSize * 2) - 1;
- if (threshold > (entries.length * 2)) {
+ if (newSize > entries.length) {
// nextPrime doesn't always return a prime larger than
// we passed in, so this block may not actually change
- // the entries size.
- newEntries = new Entry[nextPrime(threshold)];
+ // the entries size. the "-1" is to ensure we use
+ // array length 2 when going from 0 to 1.
+ newEntries = new Entry[nextPrime((newSize*2) - 1)];
} else {
newEntries = new Entry[entries.length];
}
@@ -126,7 +125,7 @@ V get(K k) {
811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009,
/* now we start skipping some, this is arbitrary */
- 2053, 3079, 4057, 7103
+ 2053, 3079, 4057, 7103, 10949, 16069, 32609, 65867, 104729
};
private final static int nextPrime(int i) {
From c08ffd25f3922343a287dbe5fd76ed9035b4d5f6 Mon Sep 17 00:00:00 2001
From: Sam Holeman
Date: Fri, 10 Aug 2018 15:07:23 -0700
Subject: [PATCH 32/83] Tweak BadMap, add tests
---
.../java/com/typesafe/config/impl/BadMap.java | 34 ++++---
.../typesafe/config/impl/ResolveMemos.java | 5 +-
.../com/typesafe/config/impl/BadMapTest.scala | 94 +++++++++++++++++++
3 files changed, 111 insertions(+), 22 deletions(-)
create mode 100644 config/src/test/scala/com/typesafe/config/impl/BadMapTest.scala
diff --git a/config/src/main/java/com/typesafe/config/impl/BadMap.java b/config/src/main/java/com/typesafe/config/impl/BadMap.java
index 0c59eba9d..04b375367 100644
--- a/config/src/main/java/com/typesafe/config/impl/BadMap.java
+++ b/config/src/main/java/com/typesafe/config/impl/BadMap.java
@@ -29,13 +29,13 @@ else if (next != null)
}
}
- final int size;
- final Entry[] entries;
+ private final int size;
+ private final Entry[] entries;
private final static Entry[] emptyEntries = {};
BadMap() {
- this(0, (Entry[]) emptyEntries);
+ this(0, emptyEntries);
}
private BadMap(int size, Entry[] entries) {
@@ -51,19 +51,20 @@ BadMap copyingPut(K k, V v) {
// we passed in, so this block may not actually change
// the entries size. the "-1" is to ensure we use
// array length 2 when going from 0 to 1.
- newEntries = new Entry[nextPrime((newSize*2) - 1)];
+ newEntries = new Entry[nextPrime((newSize * 2) - 1)];
} else {
newEntries = new Entry[entries.length];
}
- if (newEntries.length == entries.length)
+ if (newEntries.length == entries.length) {
System.arraycopy(entries, 0, newEntries, 0, entries.length);
- else
+ } else {
rehash(entries, newEntries);
+ }
int hash = Math.abs(k.hashCode());
store(newEntries, hash, k, v);
- return new BadMap(newSize, newEntries);
+ return new BadMap<>(newSize, newEntries);
}
private static void store(Entry[] entries, int hash, K k, V v) {
@@ -72,7 +73,7 @@ private static void store(Entry[] entries, int hash, K k, V v) {
entries[i] = new Entry(hash, k, v, old);
}
- private static void store(Entry[] entries, Entry e) {
+ private static void store(Entry[] entries, Entry e) {
int i = e.hash % entries.length;
Entry old = entries[i]; // old may be null
if (old == null && e.next == null) {
@@ -84,15 +85,12 @@ private static void store(Entry[] entries, Entry e) {
}
}
- private static void rehash(Entry[] src, Entry[] dest) {
- for (Entry old : src) {
- if (old != null) {
- if (old.next == null) {
- store(dest, old);
- } else {
- store(dest, old.hash, old.key, old.value);
- store(dest, old.next);
- }
+ private static void rehash(Entry[] src, Entry[] dest) {
+ for (Entry entry : src) {
+ // have to store each "next" element individually; they may belong in different indices
+ while (entry != null) {
+ store(dest, entry);
+ entry = entry.next;
}
}
}
@@ -128,7 +126,7 @@ V get(K k) {
2053, 3079, 4057, 7103, 10949, 16069, 32609, 65867, 104729
};
- private final static int nextPrime(int i) {
+ private static int nextPrime(int i) {
for (int p : primes) {
if (p > i)
return p;
diff --git a/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java b/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java
index 4fe96b3ea..941d44f65 100644
--- a/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java
+++ b/config/src/main/java/com/typesafe/config/impl/ResolveMemos.java
@@ -1,8 +1,5 @@
package com.typesafe.config.impl;
-import java.util.HashMap;
-import java.util.Map;
-
/**
* This exists because we have to memoize resolved substitutions as we go
* through the config tree; otherwise we could end up creating multiple copies
@@ -18,7 +15,7 @@ private ResolveMemos(BadMap memos) {
}
ResolveMemos() {
- this(new BadMap());
+ this(new BadMap<>());
}
AbstractConfigValue get(MemoKey key) {
diff --git a/config/src/test/scala/com/typesafe/config/impl/BadMapTest.scala b/config/src/test/scala/com/typesafe/config/impl/BadMapTest.scala
new file mode 100644
index 000000000..bfc7af173
--- /dev/null
+++ b/config/src/test/scala/com/typesafe/config/impl/BadMapTest.scala
@@ -0,0 +1,94 @@
+package com.typesafe.config.impl
+
+import org.junit.Assert._
+import org.junit.Test
+
+class BadMapTest extends TestUtils {
+ @Test
+ def copyingPut(): Unit = {
+ val map = new BadMap[String, String]()
+ val copy = map.copyingPut("key", "value")
+
+ assertNull(map.get("key"))
+ assertEquals("value", copy.get("key"))
+ }
+
+ @Test
+ def retrieveOldElement(): Unit = {
+ val map = new BadMap[String, String]()
+ .copyingPut("key1", "value1")
+ .copyingPut("key2", "value2")
+ .copyingPut("key3", "value3")
+
+ assertEquals("value1", map.get("key1"))
+ assertEquals("value2", map.get("key2"))
+ assertEquals("value3", map.get("key3"))
+ }
+
+ @Test
+ def putOverride(): Unit = {
+ val map = new BadMap[String, String]()
+ .copyingPut("key", "value1")
+ .copyingPut("key", "value2")
+ .copyingPut("key", "value3")
+
+ assertEquals("value3", map.get("key"))
+ }
+
+ @Test
+ def notFound(): Unit = {
+ val map = new BadMap[String, String]()
+
+ assertNull(map.get("invalid key"))
+ }
+
+ @Test
+ def putMany(): Unit = {
+ val entries = (1 to 1000).map(i => (s"key$i", s"value$i"))
+ var map = new BadMap[String, String]()
+
+ for ((key, value) <- entries) {
+ map = map.copyingPut(key, value)
+ }
+
+ for ((key, value) <- entries) {
+ assertEquals(value, map.get(key))
+ }
+ }
+
+ @Test
+ def putSameHash(): Unit = {
+ val hash = 2
+ val entries = (1 to 10).map(i => (new UniqueKeyWithHash(hash), s"value$i"))
+ var map = new BadMap[UniqueKeyWithHash, String]()
+
+ for ((key, value) <- entries) {
+ map = map.copyingPut(key, value)
+ }
+
+ for ((key, value) <- entries) {
+ assertEquals(value, map.get(key))
+ }
+ }
+
+ @Test
+ def putSameHashModLength(): Unit = {
+ // given that the table will eventually be the following size, we insert entries who should
+ // eventually all share the same index and then later be redistributed once rehashed
+ val size = 11
+ val entries = (1 to size * 2).map(i => (new UniqueKeyWithHash(size * i), s"value$i"))
+ var map = new BadMap[UniqueKeyWithHash, String]()
+
+ for ((key, value) <- entries) {
+ map = map.copyingPut(key, value)
+ }
+
+ for ((key, value) <- entries) {
+ assertEquals(value, map.get(key))
+ }
+ }
+
+ private class UniqueKeyWithHash(hash: Int) {
+ override def hashCode(): Int = hash
+ }
+}
From f46ab201879687d51970fa34f7855b34a0823be0 Mon Sep 17 00:00:00 2001
From: "k.bigwheel"
Date: Wed, 15 Aug 2018 04:10:13 +0900
Subject: [PATCH 33/83] Remove nbsp that breaking Markdown rendering
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e35c756b4..88c1559ba 100644
--- a/README.md
+++ b/README.md
@@ -837,7 +837,7 @@ format.
* Ficus https://github.com/ceedubs/ficus
* configz https://github.com/arosien/configz
* configs https://github.com/kxbmap/configs
- * config-annotation https://github.com/zhongl/config-annotation
+ * config-annotation https://github.com/zhongl/config-annotation
* PureConfig https://github.com/pureconfig/pureconfig
* Simple Scala Config https://github.com/ElderResearch/ssc
* konfig https://github.com/vpon/konfig
From 56c7d75aec75088616d8dbe054506450bbc56cc0 Mon Sep 17 00:00:00 2001
From: vgolub
Date: Fri, 7 Sep 2018 18:13:23 +0300
Subject: [PATCH 34/83] #584 Add root config origin to exception
---
.../src/main/java/com/typesafe/config/ConfigException.java | 5 +++++
config/src/main/java/com/typesafe/config/impl/Path.java | 4 ++--
.../src/main/java/com/typesafe/config/impl/SimpleConfig.java | 2 +-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/ConfigException.java b/config/src/main/java/com/typesafe/config/ConfigException.java
index fce04b407..f781b3755 100644
--- a/config/src/main/java/com/typesafe/config/ConfigException.java
+++ b/config/src/main/java/com/typesafe/config/ConfigException.java
@@ -8,6 +8,7 @@
import java.lang.reflect.Field;
import com.typesafe.config.impl.ConfigImplUtil;
+import com.typesafe.config.impl.Path;
/**
* All exceptions thrown by the library are subclasses of
@@ -126,6 +127,10 @@ public Missing(String path, Throwable cause) {
cause);
}
+ public Missing(ConfigOrigin origin, Path path) {
+ this(origin, "No configuration setting found for key '" + path.render() + "'");
+ }
+
public Missing(String path) {
this(path, null);
}
diff --git a/config/src/main/java/com/typesafe/config/impl/Path.java b/config/src/main/java/com/typesafe/config/impl/Path.java
index d39a57c68..1e0fd7471 100644
--- a/config/src/main/java/com/typesafe/config/impl/Path.java
+++ b/config/src/main/java/com/typesafe/config/impl/Path.java
@@ -7,7 +7,7 @@
import com.typesafe.config.ConfigException;
-final class Path {
+public final class Path {
final private String first;
final private Path remainder;
@@ -216,7 +216,7 @@ public String toString() {
* toString() is a debugging-oriented version while this is an
* error-message-oriented human-readable one.
*/
- String render() {
+ public String render() {
StringBuilder sb = new StringBuilder();
appendToStringBuilder(sb);
return sb.toString();
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 ce1913adb..308d14ca7 100644
--- a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
+++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
@@ -153,7 +153,7 @@ static private AbstractConfigValue findKeyOrNull(AbstractConfigObject self, Stri
ConfigValueType expected, Path originalPath) {
AbstractConfigValue v = self.peekAssumingResolved(key, originalPath);
if (v == null)
- throw new ConfigException.Missing(originalPath.render());
+ throw new ConfigException.Missing(self.origin(), originalPath);
if (expected != null)
v = DefaultTransformer.transform(v, expected);
From c2c6303a32a0d63daec3cf75c4548dfe02147206 Mon Sep 17 00:00:00 2001
From: vgolub
Date: Fri, 7 Sep 2018 20:25:46 +0300
Subject: [PATCH 35/83] Do not pass Path object as exception argument
---
.../main/java/com/typesafe/config/ConfigException.java | 8 ++------
config/src/main/java/com/typesafe/config/impl/Path.java | 4 ++--
.../main/java/com/typesafe/config/impl/SimpleConfig.java | 2 +-
3 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/ConfigException.java b/config/src/main/java/com/typesafe/config/ConfigException.java
index f781b3755..f35e8dbea 100644
--- a/config/src/main/java/com/typesafe/config/ConfigException.java
+++ b/config/src/main/java/com/typesafe/config/ConfigException.java
@@ -8,7 +8,6 @@
import java.lang.reflect.Field;
import com.typesafe.config.impl.ConfigImplUtil;
-import com.typesafe.config.impl.Path;
/**
* All exceptions thrown by the library are subclasses of
@@ -127,8 +126,8 @@ public Missing(String path, Throwable cause) {
cause);
}
- public Missing(ConfigOrigin origin, Path path) {
- this(origin, "No configuration setting found for key '" + path.render() + "'");
+ public Missing(ConfigOrigin origin, String path) {
+ this(origin, "No configuration setting found for key '" + path + "'", null);
}
public Missing(String path) {
@@ -139,9 +138,6 @@ protected Missing(ConfigOrigin origin, String message, Throwable cause) {
super(origin, message, cause);
}
- protected Missing(ConfigOrigin origin, String message) {
- this(origin, message, null);
- }
}
/**
diff --git a/config/src/main/java/com/typesafe/config/impl/Path.java b/config/src/main/java/com/typesafe/config/impl/Path.java
index 1e0fd7471..d39a57c68 100644
--- a/config/src/main/java/com/typesafe/config/impl/Path.java
+++ b/config/src/main/java/com/typesafe/config/impl/Path.java
@@ -7,7 +7,7 @@
import com.typesafe.config.ConfigException;
-public final class Path {
+final class Path {
final private String first;
final private Path remainder;
@@ -216,7 +216,7 @@ public String toString() {
* toString() is a debugging-oriented version while this is an
* error-message-oriented human-readable one.
*/
- public String render() {
+ String render() {
StringBuilder sb = new StringBuilder();
appendToStringBuilder(sb);
return sb.toString();
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 308d14ca7..c0d6b65c7 100644
--- a/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
+++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
@@ -153,7 +153,7 @@ static private AbstractConfigValue findKeyOrNull(AbstractConfigObject self, Stri
ConfigValueType expected, Path originalPath) {
AbstractConfigValue v = self.peekAssumingResolved(key, originalPath);
if (v == null)
- throw new ConfigException.Missing(self.origin(), originalPath);
+ throw new ConfigException.Missing(self.origin(), originalPath.render());
if (expected != null)
v = DefaultTransformer.transform(v, expected);
From 87cf1f1ba309aae03d7e4aed3d0db7e5f328341c Mon Sep 17 00:00:00 2001
From: Eugene Yokota
Date: Mon, 17 Sep 2018 00:27:44 -0400
Subject: [PATCH 36/83] Remove bad resolver
Ref https://github.com/sbt/sbt/issues/4363
http://scala-tools.org/repo-snapshots/ is no longer a valid resolver. Since it now redirects to https://blog.goodstuff.im/repo-snapshots, it causes "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target"
---
config/build.sbt | 2 --
1 file changed, 2 deletions(-)
diff --git a/config/build.sbt b/config/build.sbt
index 59e80a43a..a588d747e 100644
--- a/config/build.sbt
+++ b/config/build.sbt
@@ -12,8 +12,6 @@ crossPaths := false
libraryDependencies += "net.liftweb" %% "lift-json" % "2.5" % "test"
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
-externalResolvers += "Scala Tools Snapshots" at "http://scala-tools.org/repo-snapshots/"
-
checkstyleConfigLocation := CheckstyleConfigLocation.File((baseDirectory.value / "checkstyle-config.xml").toString)
checkstyle in Compile := {
From 3a1ffb1af77751ca23e5e315d0c38f159619517d Mon Sep 17 00:00:00 2001
From: Eugene Yokota
Date: Mon, 17 Sep 2018 00:30:55 -0400
Subject: [PATCH 37/83] Refactor build to unified slash syntax
---
build.sbt | 189 ++++++++++++++++++++++----------
config/build.sbt | 68 ------------
project/PublishToSonatype.scala | 48 --------
project/plugins.sbt | 1 +
4 files changed, 132 insertions(+), 174 deletions(-)
delete mode 100644 config/build.sbt
delete mode 100644 project/PublishToSonatype.scala
diff --git a/build.sbt b/build.sbt
index e9040beff..07ab4b181 100644
--- a/build.sbt
+++ b/build.sbt
@@ -4,62 +4,145 @@
// Release tags should follow: http://semver.org/
import scalariform.formatter.preferences._
-enablePlugins(GitVersioning)
-git.baseVersion := "1.3.0"
-
-organization in GlobalScope := "com.typesafe"
-
-scalacOptions in GlobalScope in Compile := Seq("-unchecked", "-deprecation", "-feature")
-scalacOptions in GlobalScope in Test := Seq("-unchecked", "-deprecation", "-feature")
-
-scalaVersion in ThisBuild := "2.10.4"
-
-val sonatype = new PublishToSonatype {
- def projectUrl = "https://github.com/lightbend/config"
- def developerId = "havocp"
- def developerName = "Havoc Pennington"
- def developerUrl = "http://ometer.com/"
- def scmUrl = "git://github.com/lightbend/config.git"
-}
-
-lazy val commonSettings: Seq[Setting[_]] = Def.settings(
- unpublished,
- scalariformPreferences := scalariformPreferences.value
- .setPreference(IndentSpaces, 4)
- .setPreference(FirstArgumentOnNewline, Preserve)
+ThisBuild / git.baseVersion := "1.3.0"
+ThisBuild / organization := "com.typesafe"
+ThisBuild / Compile / scalacOptions := List("-unchecked", "-deprecation", "-feature")
+ThisBuild / Test / scalacOptions := List("-unchecked", "-deprecation", "-feature")
+ThisBuild / scalaVersion := "2.10.6"
+
+ThisBuild / scmInfo := Option(
+ ScmInfo(url("https://github.com/lightbend/config"), "scm:git@github.com:lightbend/config.git")
+)
+ThisBuild / developers := List(
+ Developer(
+ id = "havocp",
+ name = "Havoc Pennington",
+ email = "@havocp",
+ url = url("http://ometer.com/")
+ )
)
+ThisBuild / description := "configuration library for JVM languages using HOCON files"
+ThisBuild / licenses := List("Apache-2.0" -> url("https://www.apache.org/licenses/LICENSE-2.0"))
+ThisBuild / homepage := Option(url("https://github.com/lightbend/config"))
+ThisBuild / pomIncludeRepository := { _ => false }
+ThisBuild / publishTo := {
+ val nexus = "https://oss.sonatype.org/"
+ if ((ThisBuild / isSnapshot).value) Option("Sonatype OSS Snapshots" at nexus + "content/repositories/snapshots")
+ else Option("Sonatype OSS Staging" at nexus + "service/local/staging/deploy/maven2")
+}
+ThisBuild / publishMavenStyle := true
lazy val root = (project in file("."))
- .settings(
- commonSettings,
- aggregate in doc := false,
- doc := (doc in (configLib, Compile)).value,
- aggregate in packageDoc := false,
- packageDoc := (packageDoc in (configLib, Compile)).value,
- aggregate in checkstyle := false,
- checkstyle := (checkstyle in (configLib, Compile)).value
- )
+ .enablePlugins(GitVersioning)
.aggregate(
testLib, configLib,
simpleLibScala, simpleAppScala, complexAppScala,
simpleLibJava, simpleAppJava, complexAppJava
)
+ .settings(commonSettings)
+ .settings(nocomma {
+ name := "config-root"
+ git.baseVersion := (ThisBuild / git.baseVersion).value
+ doc / aggregate := false
+ doc := (configLib / Compile / doc).value
+ packageDoc / aggregate := false
+ packageDoc := (configLib / Compile / packageDoc).value
+ checkstyle / aggregate := false
+ checkstyle := (configLib / Compile / checkstyle).value
+ useGpg := true
+ PgpKeys.publishSigned / aggregate := false
+ PgpKeys.publishSigned := (PgpKeys.publishSigned in configLib).value
+ PgpKeys.publishLocalSigned / aggregate := false
+ PgpKeys.publishLocalSigned := (PgpKeys.publishLocalSigned in configLib).value
+ })
lazy val configLib = Project("config", file("config"))
- .settings(
- sonatype.settings,
- osgiSettings,
- OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl"),
- publish := sys.error("use publishSigned instead of plain publish"),
- publishLocal := sys.error("use publishLocalSigned instead of plain publishLocal"),
- packageOptions in (Compile, packageBin) +=
- Package.ManifestAttributes("Automatic-Module-Name" -> "typesafe.config" ),
- scalariformPreferences := scalariformPreferences.value
- .setPreference(IndentSpaces, 4)
- .setPreference(FirstArgumentOnNewline, Preserve)
- )
.enablePlugins(SbtOsgi)
.dependsOn(testLib % "test->test")
+ .settings(osgiSettings)
+ .settings(nocomma {
+ autoScalaLibrary := false
+ crossPaths := false
+ libraryDependencies += "net.liftweb" %% "lift-json" % "2.5" % Test
+ libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test
+
+ Compile / compile / javacOptions ++= Seq("-source", "1.8", "-target", "1.8",
+ "-g", "-Xlint:unchecked")
+
+ Compile / doc / javacOptions ++= Seq("-group", s"Public API (version ${version.value})", "com.typesafe.config:com.typesafe.config.parser",
+ "-group", "Internal Implementation - Not ABI Stable", "com.typesafe.config.impl")
+ javadocSourceBaseUrl := {
+ for (gitHead <- com.typesafe.sbt.SbtGit.GitKeys.gitHeadCommit.value)
+ yield s"https://github.com/lightbend/config/blob/$gitHead/config/src/main/java"
+ }
+ // because we test some global state such as singleton caches,
+ // we have to run tests in serial.
+ Test / parallelExecution := false
+
+ test / fork := true
+ Test / fork := true
+ run / fork := true
+ Test/ run / fork := true
+
+ //env vars for tests
+ Test / envVars ++= Map("testList.0" -> "0", "testList.1" -> "1")
+
+ OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl")
+ publish := sys.error("use publishSigned instead of plain publish")
+ publishLocal := sys.error("use publishLocalSigned instead of plain publishLocal")
+ Compile / packageBin / packageOptions +=
+ Package.ManifestAttributes("Automatic-Module-Name" -> "typesafe.config" )
+ scalariformPreferences := scalariformPreferences.value
+ .setPreference(IndentSpaces, 4)
+ .setPreference(FirstArgumentOnNewline, Preserve)
+
+ checkstyleConfigLocation := CheckstyleConfigLocation.File((baseDirectory.value / "checkstyle-config.xml").toString)
+
+ Compile / checkstyle := {
+ val log = streams.value.log
+ (Compile / checkstyle).value
+ val resultFile = (Compile / checkstyleOutputFile).value
+ val results = scala.xml.XML.loadFile(resultFile)
+ val errorFiles = results \\ "checkstyle" \\ "file"
+
+ def errorFromXml(node: scala.xml.NodeSeq): (String, String, String) = {
+ val line: String = (node \ "@line" text)
+ val msg: String = (node \ "@message" text)
+ val source: String = (node \ "@source" text)
+ (line, msg, source)
+ }
+ def errorsFromXml(fileNode: scala.xml.NodeSeq): Seq[(String, String, String, String)] = {
+ val name: String = (fileNode \ "@name" text)
+ val errors = (fileNode \\ "error") map { e => errorFromXml(e) }
+ errors map { case (line, error, source) => (name, line, error, source) }
+ }
+
+ val errors = errorFiles flatMap { f => errorsFromXml(f) }
+
+ if (errors.nonEmpty) {
+ for (e <- errors) {
+ log.error(s"${e._1}:${e._2}: ${e._3} (from ${e._4})")
+ }
+ throw new RuntimeException(s"Checkstyle failed with ${errors.size} errors")
+ }
+ log.info("No errors from checkstyle")
+ }
+
+ // add checkstyle as a dependency of doc
+ Compile / doc := ((Compile / doc).dependsOn(Compile / checkstyle)).value
+
+ findbugsReportType := Some(FindbugsReport.Html)
+ findbugsReportPath := Some(crossTarget.value / "findbugs.html")
+ findbugsEffort := FindbugsEffort.Maximum
+ findbugsMaxMemory := 2000
+ })
+
+lazy val commonSettings: Seq[Setting[_]] = Def.settings(
+ unpublished,
+ scalariformPreferences := scalariformPreferences.value
+ .setPreference(IndentSpaces, 4)
+ .setPreference(FirstArgumentOnNewline, Preserve)
+)
def proj(id: String, base: File) = Project(id, base) settings commonSettings
@@ -73,23 +156,13 @@ lazy val simpleLibJava = proj("config-simple-lib-java", file("examples/java/si
lazy val simpleAppJava = proj("config-simple-app-java", file("examples/java/simple-app")) dependsOn simpleLibJava
lazy val complexAppJava = proj("config-complex-app-java", file("examples/java/complex-app")) dependsOn simpleLibJava
-useGpg := true
-
-aggregate in PgpKeys.publishSigned := false
-PgpKeys.publishSigned := (PgpKeys.publishSigned in configLib).value
-
-aggregate in PgpKeys.publishLocalSigned := false
-PgpKeys.publishLocalSigned := (PgpKeys.publishLocalSigned in configLib).value
-
val unpublished = Seq(
// no artifacts in this project
- publishArtifact := false,
+ publishArtifact := false,
// make-pom has a more specific publishArtifact setting already
// so needs specific override
- publishArtifact in makePom := false,
+ makePom / publishArtifact := false,
// no docs to publish
- publishArtifact in packageDoc := false,
- // can't seem to get rid of ivy files except by no-op'ing the entire publish task
- publish := {},
- publishLocal := {}
+ packageDoc / publishArtifact := false,
+ publish / skip := true
)
diff --git a/config/build.sbt b/config/build.sbt
deleted file mode 100644
index a588d747e..000000000
--- a/config/build.sbt
+++ /dev/null
@@ -1,68 +0,0 @@
-fork in test := true
-fork in Test := true
-fork in run := true
-fork in run in Test := true
-
-//env vars for tests
-envVars in Test ++= Map("testList.0" -> "0", "testList.1" -> "1")
-
-autoScalaLibrary := false
-crossPaths := false
-
-libraryDependencies += "net.liftweb" %% "lift-json" % "2.5" % "test"
-libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test"
-
-checkstyleConfigLocation := CheckstyleConfigLocation.File((baseDirectory.value / "checkstyle-config.xml").toString)
-
-checkstyle in Compile := {
- val log = streams.value.log
- (checkstyle in Compile).value
- val resultFile = (checkstyleOutputFile in Compile).value
- val results = scala.xml.XML.loadFile(resultFile)
- val errorFiles = results \\ "checkstyle" \\ "file"
-
- def errorFromXml(node: scala.xml.NodeSeq): (String, String, String) = {
- val line: String = (node \ "@line" text)
- val msg: String = (node \ "@message" text)
- val source: String = (node \ "@source" text)
- (line, msg, source)
- }
- def errorsFromXml(fileNode: scala.xml.NodeSeq): Seq[(String, String, String, String)] = {
- val name: String = (fileNode \ "@name" text)
- val errors = (fileNode \\ "error") map { e => errorFromXml(e) }
- errors map { case (line, error, source) => (name, line, error, source) }
- }
-
- val errors = errorFiles flatMap { f => errorsFromXml(f) }
-
- if (errors.nonEmpty) {
- for (e <- errors) {
- log.error(s"${e._1}:${e._2}: ${e._3} (from ${e._4})")
- }
- throw new RuntimeException(s"Checkstyle failed with ${errors.size} errors")
- }
- log.info("No errors from checkstyle")
-}
-
-// add checkstyle as a dependency of doc
-doc in Compile := ((doc in Compile).dependsOn(checkstyle in Compile)).value
-
-findbugsReportType := Some(FindbugsReport.Html)
-findbugsReportPath := Some(crossTarget.value / "findbugs.html")
-findbugsEffort := FindbugsEffort.Maximum
-findbugsMaxMemory := 2000
-
-javacOptions in (Compile, compile) ++= Seq("-source", "1.8", "-target", "1.8",
- "-g", "-Xlint:unchecked")
-
-// because we test some global state such as singleton caches,
-// we have to run tests in serial.
-parallelExecution in Test := false
-
-javacOptions in (Compile, doc) ++= Seq("-group", s"Public API (version ${version.value})", "com.typesafe.config:com.typesafe.config.parser",
- "-group", "Internal Implementation - Not ABI Stable", "com.typesafe.config.impl")
-
-javadocSourceBaseUrl := {
- for (gitHead <- com.typesafe.sbt.SbtGit.GitKeys.gitHeadCommit.value)
- yield s"https://github.com/lightbend/config/blob/$gitHead/config/src/main/java"
-}
diff --git a/project/PublishToSonatype.scala b/project/PublishToSonatype.scala
deleted file mode 100644
index 9c12d5cd9..000000000
--- a/project/PublishToSonatype.scala
+++ /dev/null
@@ -1,48 +0,0 @@
-import sbt._, Keys._
-
-// from https://raw.github.com/paulp/scala-improving/master/project/PublishToSonatype.scala
-abstract class PublishToSonatype {
- val ossSnapshots = "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
- val ossStaging = "Sonatype OSS Staging" at "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
-
- def projectUrl: String
- def developerId: String
- def developerName: String
- def developerUrl: String
-
- def licenseName = "Apache License, Version 2.0"
- def licenseUrl = "https://www.apache.org/licenses/LICENSE-2.0"
- def licenseDistribution = "repo"
- def scmUrl: String
- def scmConnection = "scm:git:" + scmUrl
-
- def generatePomExtra: xml.NodeSeq = {
- { projectUrl }
-
-
- { licenseName }
- { licenseUrl }
- { licenseDistribution }
-
-
-
- { scmUrl }
- { scmConnection }
-
-
-
- { developerId }
- { developerName }
- { developerUrl }
-
-
- }
-
- def settings: Seq[Setting[_]] = Seq(
- publishMavenStyle := true,
- publishTo := Some(if (isSnapshot.value) ossSnapshots else ossStaging),
- publishArtifact in Test := false,
- pomIncludeRepository := (_ => false),
- pomExtra := generatePomExtra
- )
-}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 3ed275faa..dd15b5dd1 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -7,3 +7,4 @@ addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2")
addSbtPlugin("com.etsy" % "sbt-checkstyle-plugin" % "3.1.1")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
+addSbtPlugin("com.eed3si9n" % "sbt-nocomma" % "0.1.0")
From 362b7ecccd85d1bef45e41862b83f216712a3f65 Mon Sep 17 00:00:00 2001
From: Eric Richardson
Date: Thu, 1 Nov 2018 11:24:34 -0400
Subject: [PATCH 38/83] Fix stack trace printing in test
---
config/src/test/scala/com/typesafe/config/impl/TestUtils.scala | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
index 702c2930c..8b6787d1d 100644
--- a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
@@ -249,7 +249,7 @@ abstract trait TestUtils {
"possibly caused by http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627",
nf)
case e: Exception =>
- System.err.println(e.getStackTrace.toString);
+ e.printStackTrace(System.err)
throw new AssertionError("failed to make a copy via serialization", e)
}
From 1c23940ddd5b2296b576def5720e5fb8550ab053 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Koz=C5=82owski?=
Date: Sun, 4 Nov 2018 16:46:48 +0100
Subject: [PATCH 39/83] Add a note about classloader issues to README
---
README.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/README.md b/README.md
index 88c1559ba..cf034c778 100644
--- a/README.md
+++ b/README.md
@@ -759,6 +759,14 @@ If you have trouble with your configuration, some useful tips.
string with comments showing where each value came from.
This string can be printed out on console or logged to
a file etc.
+ - If you see errors like
+ `com.typesafe.config.ConfigException$Missing: No configuration setting found for key foo`,
+ and you're sure that key is defined in your config file, they might appear e.g.
+ when you're loading configuration from a thread that's not the JVM's main thread.
+ Try passing the `ClassLoader` to manually - e.g. with `ConfigFactory.load(getClass().getClassLoader())`.
+ If you don't pass one, Lightbend Config uses the calling thread's `contextClassLoader`, and in some cases,
+ it may not have your configuration files in its classpath,
+ so loading the config on that thread can yield unexpected, erroneous results.
### Supports Java 8 and Later
From a7625e5387fe39081f6ac0083854c9bfede34b4d Mon Sep 17 00:00:00 2001
From: Havoc Pennington
Date: Sun, 4 Nov 2018 17:00:15 +0100
Subject: [PATCH 40/83] Update README.md
Co-Authored-By: kubukoz
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index cf034c778..6c340120c 100644
--- a/README.md
+++ b/README.md
@@ -763,7 +763,8 @@ If you have trouble with your configuration, some useful tips.
`com.typesafe.config.ConfigException$Missing: No configuration setting found for key foo`,
and you're sure that key is defined in your config file, they might appear e.g.
when you're loading configuration from a thread that's not the JVM's main thread.
- Try passing the `ClassLoader` to manually - e.g. with `ConfigFactory.load(getClass().getClassLoader())`.
+ Try passing the `ClassLoader` in manually - e.g. with `ConfigFactory.load(getClass().getClassLoader())`
+ or setting the context class loader.
If you don't pass one, Lightbend Config uses the calling thread's `contextClassLoader`, and in some cases,
it may not have your configuration files in its classpath,
so loading the config on that thread can yield unexpected, erroneous results.
From f3628e4c6b5e7ce8162fb5d5dce0def938fa89ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Koz=C5=82owski?=
Date: Sun, 4 Nov 2018 17:02:02 +0100
Subject: [PATCH 41/83] Remove whitespace
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 6c340120c..ea89fd62f 100644
--- a/README.md
+++ b/README.md
@@ -764,7 +764,7 @@ If you have trouble with your configuration, some useful tips.
and you're sure that key is defined in your config file, they might appear e.g.
when you're loading configuration from a thread that's not the JVM's main thread.
Try passing the `ClassLoader` in manually - e.g. with `ConfigFactory.load(getClass().getClassLoader())`
- or setting the context class loader.
+ or setting the context class loader.
If you don't pass one, Lightbend Config uses the calling thread's `contextClassLoader`, and in some cases,
it may not have your configuration files in its classpath,
so loading the config on that thread can yield unexpected, erroneous results.
From f82a1ed44c26a927a52186a9616bf79b085aeb36 Mon Sep 17 00:00:00 2001
From: hepin1989
Date: Mon, 3 Dec 2018 15:19:09 +0800
Subject: [PATCH 42/83] Update sbt to 1.2.7.
---
project/build.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project/build.properties b/project/build.properties
index 5620cc502..72f902892 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.2.1
+sbt.version=1.2.7
From 855716ae7e84cfc31c6ff68266dffbc8edb1b6cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Mela?=
Date: Sat, 5 Jan 2019 09:02:59 +0100
Subject: [PATCH 43/83] Project Scala version updated to 1.12.8; all the IDE &
compiler warnings fixed
As discussed in https://github.com/lightbend/config/pull/568 .
`lift-json` was also bumped as there was no longer any suitable version for Scala 2.12.x.
Also fixed compiler warnings (e.g. _eta expansion of parameterless methods is deprecated_) as well as some rarther non-controversial IDE warnings (e.g. redundant semicolons and such).
---
build.sbt | 4 +-
config/src/test/scala/ApiExamples.scala | 2 +-
config/src/test/scala/Profiling.scala | 26 +++++------
config/src/test/scala/Rendering.scala | 2 +-
.../typesafe/config/impl/ConfParserTest.scala | 18 ++++----
.../config/impl/ConfigBeanFactoryTest.scala | 14 +++---
.../impl/ConfigDocumentParserTest.scala | 23 +++++-----
.../config/impl/ConfigDocumentTest.scala | 4 +-
.../config/impl/ConfigSubstitutionTest.scala | 14 +++---
.../com/typesafe/config/impl/ConfigTest.scala | 45 +++++++++----------
.../config/impl/ConfigValueTest.scala | 42 ++++++++---------
.../config/impl/EquivalentsTest.scala | 2 +-
.../com/typesafe/config/impl/HttpTest.scala | 2 +-
.../com/typesafe/config/impl/JsonTest.scala | 27 +++++------
.../config/impl/ParseableReaderTest.scala | 36 +++++++--------
.../com/typesafe/config/impl/PathTest.scala | 4 +-
.../typesafe/config/impl/PropertiesTest.scala | 2 +-
.../com/typesafe/config/impl/TestUtils.scala | 2 +-
.../typesafe/config/impl/TokenizerTest.scala | 12 ++---
.../com/typesafe/config/impl/ToyHttp.scala | 9 ++--
.../typesafe/config/impl/UnitParserTest.scala | 4 +-
.../com/typesafe/config/impl/UtilTest.scala | 2 +-
.../src/main/scala/ComplexApp.scala | 2 +-
.../src/main/scala/simplelib/SimpleLib.scala | 6 +--
project/linksource.scala | 4 +-
25 files changed, 150 insertions(+), 158 deletions(-)
diff --git a/build.sbt b/build.sbt
index 07ab4b181..9d78b6aea 100644
--- a/build.sbt
+++ b/build.sbt
@@ -8,7 +8,7 @@ ThisBuild / git.baseVersion := "1.3.0"
ThisBuild / organization := "com.typesafe"
ThisBuild / Compile / scalacOptions := List("-unchecked", "-deprecation", "-feature")
ThisBuild / Test / scalacOptions := List("-unchecked", "-deprecation", "-feature")
-ThisBuild / scalaVersion := "2.10.6"
+ThisBuild / scalaVersion := "2.12.8"
ThisBuild / scmInfo := Option(
ScmInfo(url("https://github.com/lightbend/config"), "scm:git@github.com:lightbend/config.git")
@@ -63,7 +63,7 @@ lazy val configLib = Project("config", file("config"))
.settings(nocomma {
autoScalaLibrary := false
crossPaths := false
- libraryDependencies += "net.liftweb" %% "lift-json" % "2.5" % Test
+ libraryDependencies += "net.liftweb" %% "lift-json" % "3.3.0" % Test
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test
Compile / compile / javacOptions ++= Seq("-source", "1.8", "-target", "1.8",
diff --git a/config/src/test/scala/ApiExamples.scala b/config/src/test/scala/ApiExamples.scala
index 2a6fce76a..5d464dce3 100644
--- a/config/src/test/scala/ApiExamples.scala
+++ b/config/src/test/scala/ApiExamples.scala
@@ -52,7 +52,7 @@ class ApiExamples {
class EnhancedConfig(c: Config) {
def getAny(path: String): Any = c.getAnyRef(path)
}
- implicit def config2enhanced(c: Config) = new EnhancedConfig(c)
+ implicit def config2enhanced(c: Config): EnhancedConfig = new EnhancedConfig(c)
// somewhat nicer now
val e: Int = conf.getAny("ints.fortyTwo") match {
diff --git a/config/src/test/scala/Profiling.scala b/config/src/test/scala/Profiling.scala
index 5cd412ef1..e66768b5f 100644
--- a/config/src/test/scala/Profiling.scala
+++ b/config/src/test/scala/Profiling.scala
@@ -36,7 +36,7 @@ object Util {
}
def time(body: () => Unit, iterations: Int): Double = {
- timeHelper(body, iterations, false)
+ timeHelper(body, iterations, retried = false)
}
def loop(args: Seq[String], body: () => Unit) {
@@ -57,10 +57,10 @@ object FileLoad extends App {
}
}
- val ms = Util.time(task, 4000)
+ val ms = Util.time(() => task(), 4000)
println("file load: " + ms + "ms")
- Util.loop(args, task)
+ Util.loop(args, () => task())
}
object Resolve extends App {
@@ -73,10 +73,10 @@ object Resolve extends App {
}
}
- val ms = Util.time(task, 3000000)
+ val ms = Util.time(() => task(), 3000000)
println("resolve: " + ms + "ms")
- Util.loop(args, task)
+ Util.loop(args, () => task())
}
object GetExistingPath extends App {
@@ -88,10 +88,10 @@ object GetExistingPath extends App {
}
}
- val ms = Util.time(task, 2000000)
+ val ms = Util.time(() => task(), 2000000)
println("GetExistingPath: " + ms + "ms")
- Util.loop(args, task)
+ Util.loop(args, () => task())
}
object GetSeveralExistingPaths extends App {
@@ -105,10 +105,10 @@ object GetSeveralExistingPaths extends App {
}
}
- val ms = Util.time(task, 5000000)
+ val ms = Util.time(() => task(), 5000000)
println("GetSeveralExistingPaths: " + ms + "ms")
- Util.loop(args, task)
+ Util.loop(args, () => task())
}
object HasPathOnMissing extends App {
@@ -120,10 +120,10 @@ object HasPathOnMissing extends App {
}
}
- val ms = Util.time(task, 20000000)
+ val ms = Util.time(() => task(), 20000000)
println("HasPathOnMissing: " + ms + "ms")
- Util.loop(args, task)
+ Util.loop(args, () => task())
}
object CatchExceptionOnMissing extends App {
@@ -146,9 +146,9 @@ object CatchExceptionOnMissing extends App {
}
anotherStackFrame(40) { () =>
- val ms = Util.time(task, 300000)
+ val ms = Util.time(() => task(), 300000)
println("CatchExceptionOnMissing: " + ms + "ms")
- Util.loop(args, task)
+ Util.loop(args, () => task())
}
}
diff --git a/config/src/test/scala/Rendering.scala b/config/src/test/scala/Rendering.scala
index 0d8be469e..efdb0904f 100644
--- a/config/src/test/scala/Rendering.scala
+++ b/config/src/test/scala/Rendering.scala
@@ -62,7 +62,7 @@ object RenderOptions extends App {
val rendered =
allBooleanLists(4).foldLeft(0) { (count, values) =>
- val formatted = values(0)
+ val formatted = values.head
val originComments = values(1)
val comments = values(2)
val json = values(3)
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfParserTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfParserTest.scala
index 3ff873771..648e0c4ee 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfParserTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfParserTest.scala
@@ -15,14 +15,14 @@ import java.util.Properties
class ConfParserTest extends TestUtils {
- def parseWithoutResolving(s: String) = {
+ def parseWithoutResolving(s: String): AbstractConfigValue = {
val options = ConfigParseOptions.defaults().
setOriginDescription("test conf string").
setSyntax(ConfigSyntax.CONF)
- Parseable.newString(s, options).parseValue().asInstanceOf[AbstractConfigValue]
+ Parseable.newString(s, options).parseValue()
}
- def parse(s: String) = {
+ def parse(s: String): AbstractConfigValue = {
val tree = parseWithoutResolving(s)
// resolve substitutions so we can test problems with that, like cycles or
@@ -38,7 +38,7 @@ class ConfParserTest extends TestUtils {
@Test
def invalidConfThrows(): Unit = {
// be sure we throw
- for (invalid <- whitespaceVariations(invalidConf, false)) {
+ for (invalid <- whitespaceVariations(invalidConf, validInLift = false)) {
addOffendingJsonToException("config", invalid.test) {
intercept[ConfigException] {
parse(invalid.test)
@@ -152,7 +152,7 @@ class ConfParserTest extends TestUtils {
}
} catch {
case e: Throwable =>
- System.err.println("failed on: '" + invalid + "'");
+ System.err.println("failed on: '" + invalid + "'")
throw e;
}
}
@@ -267,9 +267,9 @@ class ConfParserTest extends TestUtils {
{ s: String => s.replace(",\n", " \n \n , \n \n ") },
{ s: String => dropCurlies(s) })
- var tested = 0;
+ var tested = 0
for (v <- valids; change <- changes) {
- tested += 1;
+ tested += 1
val obj = parseConfig(change(v))
assertEquals(3, obj.root.size())
assertEquals("y", obj.getString("a"))
@@ -351,7 +351,7 @@ class ConfParserTest extends TestUtils {
}
@Test
- def toStringForParseables() {
+ def toStringForParseablesWorks() {
// just be sure the toString don't throw, to get test coverage
val options = ConfigParseOptions.defaults()
Parseable.newFile(new File("foo"), options).toString
@@ -366,7 +366,7 @@ class ConfParserTest extends TestUtils {
}
private def assertComments(comments: Seq[String], conf: Config, path: String) {
- assertEquals(comments, conf.getValue(path).origin().comments().asScala.toSeq)
+ assertEquals(comments, conf.getValue(path).origin().comments().asScala)
}
private def assertComments(comments: Seq[String], conf: Config, path: String, index: Int) {
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala
index bd4b47043..b7e56ebf7 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigBeanFactoryTest.scala
@@ -7,7 +7,7 @@ import beanconfig.EnumsConfig.{ Solution, Problem }
import com.typesafe.config._
import java.io.{ InputStream, InputStreamReader }
-import java.time.Duration;
+import java.time.Duration
import beanconfig._
import org.junit.Assert._
@@ -19,7 +19,7 @@ import scala.collection.mutable.ArrayBuffer
class ConfigBeanFactoryTest extends TestUtils {
@Test
- def toCamelCase() {
+ def testToCamelCase() {
assertEquals("configProp", ConfigImplUtil.toCamelCase("config-prop"))
assertEquals("configProp", ConfigImplUtil.toCamelCase("configProp"))
assertEquals("fooBar", ConfigImplUtil.toCamelCase("foo-----bar"))
@@ -122,10 +122,10 @@ class ConfigBeanFactoryTest extends TestUtils {
ConfigMemorySize.ofBytes(1073741824)),
beanConfig.getOfMemorySize.asScala)
- val stringsConfigOne = new StringsConfig();
+ val stringsConfigOne = new StringsConfig()
stringsConfigOne.setAbcd("testAbcdOne")
stringsConfigOne.setYes("testYesOne")
- val stringsConfigTwo = new StringsConfig();
+ val stringsConfigTwo = new StringsConfig()
stringsConfigTwo.setAbcd("testAbcdTwo")
stringsConfigTwo.setYes("testYesTwo")
@@ -155,10 +155,10 @@ class ConfigBeanFactoryTest extends TestUtils {
ConfigMemorySize.ofBytes(1073741824)),
beanConfig.getOfMemorySize.asScala)
- val stringsConfigOne = new StringsConfig();
+ val stringsConfigOne = new StringsConfig()
stringsConfigOne.setAbcd("testAbcdOne")
stringsConfigOne.setYes("testYesOne")
- val stringsConfigTwo = new StringsConfig();
+ val stringsConfigTwo = new StringsConfig()
stringsConfigTwo.setAbcd("testAbcdTwo")
stringsConfigTwo.setYes("testYesTwo")
@@ -200,7 +200,7 @@ class ConfigBeanFactoryTest extends TestUtils {
assertEquals("abcd", beanConfig.getConfig.getString("abcd"))
assertEquals(3, beanConfig.getConfigObj.toConfig.getInt("intVal"))
assertEquals(stringValue("hello world"), beanConfig.getConfigValue)
- assertEquals(List(1, 2, 3).map(intValue(_)), beanConfig.getList.asScala)
+ assertEquals(List(1, 2, 3).map(intValue), beanConfig.getList.asScala)
assertEquals(true, beanConfig.getUnwrappedMap.get("shouldBeInt"))
assertEquals(42, beanConfig.getUnwrappedMap.get("should-be-boolean"))
}
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentParserTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentParserTest.scala
index fb8bca20b..9cba2eb0a 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentParserTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentParserTest.scala
@@ -1,6 +1,7 @@
package com.typesafe.config.impl
-import com.typesafe.config.{ ConfigException, ConfigSyntax, ConfigParseOptions }
+import com.typesafe.config.ConfigSyntax.JSON
+import com.typesafe.config.{ ConfigException, ConfigParseOptions, ConfigSyntax }
import org.junit.Assert._
import org.junit.Test
@@ -14,7 +15,7 @@ class ConfigDocumentParserTest extends TestUtils {
private def parseJSONFailuresTest(origText: String, containsMessage: String) {
var exceptionThrown = false
val e = intercept[ConfigException] {
- ConfigDocumentParser.parse(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
+ ConfigDocumentParser.parse(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON))
}
assertTrue(e.getMessage.contains(containsMessage))
}
@@ -25,7 +26,7 @@ class ConfigDocumentParserTest extends TestUtils {
assertEquals(expectedRenderedText, node.render())
assertTrue(node.isInstanceOf[ConfigNodeSimpleValue])
- val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
+ val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON))
assertEquals(expectedRenderedText, nodeJSON.render())
assertTrue(nodeJSON.isInstanceOf[ConfigNodeSimpleValue])
}
@@ -35,7 +36,7 @@ class ConfigDocumentParserTest extends TestUtils {
assertEquals(origText, node.render())
assertTrue(node.isInstanceOf[ConfigNodeComplexValue])
- val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
+ val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON))
assertEquals(origText, nodeJSON.render())
assertTrue(nodeJSON.isInstanceOf[ConfigNodeComplexValue])
}
@@ -45,7 +46,7 @@ class ConfigDocumentParserTest extends TestUtils {
assertEquals(origText, node.render())
val e = intercept[ConfigException] {
- ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
+ ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON))
}
assertTrue(e.getMessage.contains(containsMessage))
}
@@ -58,7 +59,7 @@ class ConfigDocumentParserTest extends TestUtils {
}
@Test
- def parseSuccess {
+ def parseSuccess() {
parseTest("foo:bar")
parseTest(" foo : bar ")
parseTest("""include "foo.conf" """)
@@ -185,7 +186,7 @@ class ConfigDocumentParserTest extends TestUtils {
]
}
"""
- val node = ConfigDocumentParser.parse(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
+ val node = ConfigDocumentParser.parse(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON))
assertEquals(origText, node.render())
}
@@ -249,7 +250,7 @@ class ConfigDocumentParserTest extends TestUtils {
}
@Test
- def parseSingleValuesFailures {
+ def parseSingleValuesFailures() {
// Parse Simple Value throws on leading and trailing whitespace, comments, or newlines
parseLeadingTrailingFailure(" 123")
parseLeadingTrailingFailure("123 ")
@@ -267,17 +268,17 @@ class ConfigDocumentParserTest extends TestUtils {
// Check that concatenations in JSON will throw an error
var origText = "123 456 \"abc\""
- var e = intercept[ConfigException] { ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON)) }
+ var e = intercept[ConfigException] { ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON)) }
assertTrue("expected message for parsing concat as json", e.getMessage.contains("Parsing JSON and the value set in withValueText was either a concatenation or had trailing whitespace, newlines, or comments"))
// Check that keys with no separators and object values in JSON will throw an error
origText = """{"foo" { "bar" : 12 } }"""
- e = intercept[ConfigException] { ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax((ConfigSyntax.JSON))) }
+ e = intercept[ConfigException] { ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(JSON)) }
assertTrue("expected failure for key foo followed by token", e.getMessage.contains("""Key '"foo"' may not be followed by token: '{'"""))
}
@Test
- def parseEmptyDocument {
+ def parseEmptyDocument() {
val node = ConfigDocumentParser.parse(tokenize(""), fakeOrigin(), ConfigParseOptions.defaults())
assertTrue(node.value().isInstanceOf[ConfigNodeObject])
assertTrue(node.value().children().isEmpty())
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentTest.scala
index 1106f6041..8811d64b4 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigDocumentTest.scala
@@ -28,7 +28,7 @@ class ConfigDocumentTest extends TestUtils {
}
@Test
- def configDocumentReplace {
+ def configDocumentReplace() {
// Can handle parsing/replacement with a very simple map
configDocumentReplaceConfTest("""{"a":1}""", """{"a":2}""", "2", "a")
configDocumentReplaceJsonTest("""{"a":1}""", """{"a":2}""", "2", "a")
@@ -37,7 +37,7 @@ class ConfigDocumentTest extends TestUtils {
configDocumentReplaceConfTest("a: b\nc = d", "a: b\nc = 12", "12", "c")
// Can handle parsing/replacement with a complicated map
- var origText =
+ val origText =
"""{
"a":123,
"b": 123.456,
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigSubstitutionTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigSubstitutionTest.scala
index 712e1c438..61047c405 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigSubstitutionTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigSubstitutionTest.scala
@@ -79,7 +79,7 @@ class ConfigSubstitutionTest extends TestUtils {
def resolveNull() {
val s = subst("bar.null")
val v = resolveWithoutFallbacks(s, simpleObject)
- assertEquals(nullValue(), v)
+ assertEquals(nullValue, v)
}
@Test
@@ -126,13 +126,13 @@ class ConfigSubstitutionTest extends TestUtils {
@Test
def resolveMissingInString() {
- val s = substInString("bar.missing", true /* optional */ )
+ val s = substInString("bar.missing", optional = true)
val v = resolveWithoutFallbacks(s, simpleObject)
// absent object becomes empty string
assertEquals(stringValue("start<>end"), v)
intercept[ConfigException.UnresolvedSubstitution] {
- val s2 = substInString("bar.missing", false /* optional */ )
+ val s2 = substInString("bar.missing", optional = false)
resolveWithoutFallbacks(s2, simpleObject)
}
}
@@ -654,9 +654,9 @@ class ConfigSubstitutionTest extends TestUtils {
values.put("a", child.relativized(new Path("a")))
// this "foo" should NOT be used.
- values.put("foo", stringValue("in parent"));
+ values.put("foo", stringValue("in parent"))
- val resolved = resolve(new SimpleConfigObject(fakeOrigin(), values));
+ val resolved = resolve(new SimpleConfigObject(fakeOrigin(), values))
assertEquals("in child", resolved.getString("a.bar"))
}
@@ -670,9 +670,9 @@ class ConfigSubstitutionTest extends TestUtils {
values.put("a", child.relativized(new Path("a")))
// so this "foo" SHOULD be used
- values.put("foo", stringValue("in parent"));
+ values.put("foo", stringValue("in parent"))
- val resolved = resolve(new SimpleConfigObject(fakeOrigin(), values));
+ val resolved = resolve(new SimpleConfigObject(fakeOrigin(), values))
assertEquals("in parent", resolved.getString("a.bar"))
}
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 0becca4bc..1bf031ba3 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -25,7 +25,7 @@ class ConfigTest extends TestUtils {
ConfigResolveOptions.noSystem()).asInstanceOf[AbstractConfigObject].toConfig
}
- def mergeUnresolved(toMerge: AbstractConfigObject*) = {
+ def mergeUnresolved(toMerge: AbstractConfigObject*): AbstractConfigObject = {
if (toMerge.isEmpty) {
SimpleConfigObject.empty()
} else {
@@ -33,7 +33,7 @@ class ConfigTest extends TestUtils {
}
}
- def merge(toMerge: AbstractConfigObject*) = {
+ def merge(toMerge: AbstractConfigObject*): AbstractConfigObject = {
val obj = mergeUnresolved(toMerge: _*)
resolveNoSystem(obj, obj) match {
case x: AbstractConfigObject => x
@@ -46,34 +46,31 @@ class ConfigTest extends TestUtils {
def makeTrees(objects: Seq[AbstractConfigObject]): Iterator[AbstractConfigObject] = {
objects.length match {
case 0 => Iterator.empty
- case 1 => {
+ case 1 =>
Iterator(objects(0))
- }
- case 2 => {
+ case 2 =>
Iterator(objects(0).withFallback(objects(1)))
- }
- case n => {
+ case n =>
val leftSplits = for {
- i <- (1 until n)
+ i <- 1 until n
pair = objects.splitAt(i)
first = pair._1.reduceLeft(_.withFallback(_))
second = pair._2.reduceLeft(_.withFallback(_))
} yield first.withFallback(second)
val rightSplits = for {
- i <- (1 until n)
+ i <- 1 until n
pair = objects.splitAt(i)
first = pair._1.reduceRight(_.withFallback(_))
second = pair._2.reduceRight(_.withFallback(_))
} yield first.withFallback(second)
leftSplits.iterator ++ rightSplits.iterator
- }
}
}
val trees = makeTrees(allObjects).toSeq
for (tree <- trees) {
// if this fails, we were not associative.
- if (!trees(0).equals(tree))
+ if (!trees.head.equals(tree))
throw new AssertionError("Merge was not associative, " +
"verify that it should not be, then don't use associativeMerge " +
"for this one. two results were: \none: " + trees(0) + "\ntwo: " +
@@ -352,7 +349,7 @@ class ConfigTest extends TestUtils {
val fixUpCycle = parseObject(""" { "a" : { "b" : { "c" : 57 } } } """)
val merged = mergeUnresolved(fixUpCycle, cycleObject)
val v = resolveNoSystem(subst("foo"), merged)
- assertEquals(intValue(57), v);
+ assertEquals(intValue(57), v)
}
@Test
@@ -402,7 +399,7 @@ class ConfigTest extends TestUtils {
val resolved = resolveNoSystem(merged, merged)
assertEquals(3, resolved.root.size())
- assertEquals(42, resolved.getInt("j"));
+ assertEquals(42, resolved.getInt("j"))
assertEquals(2, resolved.getInt("b.y"))
assertEquals(3, resolved.getInt("c.z"))
}
@@ -568,7 +565,7 @@ class ConfigTest extends TestUtils {
// to get null we have to use the get() method from Map,
// which takes a key and not a path
- assertEquals(nullValue(), conf.getObject("nulls").get("null"))
+ assertEquals(nullValue, conf.getObject("nulls").get("null"))
assertNull(conf.root.get("notinthefile"))
// get stuff with getValue
@@ -951,8 +948,8 @@ class ConfigTest extends TestUtils {
// include should have overridden the "ints" value in test03
assertEquals(42, conf.getInt("test01.ints.fortyTwo"))
// include should have been overridden by 42
- assertEquals(42, conf.getInt("test01.booleans"));
- assertEquals(42, conf.getInt("test01.booleans"));
+ assertEquals(42, conf.getInt("test01.booleans"))
+ assertEquals(42, conf.getInt("test01.booleans"))
// include should have gotten .properties and .json also
assertEquals("abc", conf.getString("test01.fromProps.abc"))
assertEquals("A", conf.getString("test01.fromJsonA"))
@@ -983,10 +980,10 @@ class ConfigTest extends TestUtils {
// check that includes into the root object work and that
// "substitutions look relative-to-included-file first then at root second" works
- assertEquals("This is in the included file", conf.getString("a"));
- assertEquals("This is in the including file", conf.getString("b"));
- assertEquals("This is in the included file", conf.getString("subtree.a"));
- assertEquals("This is in the including file", conf.getString("subtree.b"));
+ assertEquals("This is in the included file", conf.getString("a"))
+ assertEquals("This is in the including file", conf.getString("b"))
+ assertEquals("This is in the included file", conf.getString("subtree.a"))
+ assertEquals("This is in the including file", conf.getString("subtree.b"))
}
@Test
@@ -1107,11 +1104,11 @@ class ConfigTest extends TestUtils {
.setOriginComments(originComments)
.setComments(comments)
.setJson(json)
- }.toSeq
+ }
for (i <- 1 to 10) {
val numString = i.toString
- val name = "/test" + { if (numString.size == 1) "0" else "" } + numString
+ val name = "/test" + { if (numString.length == 1) "0" else "" } + numString
val conf = ConfigFactory.parseResourcesAnySyntax(classOf[ConfigTest], name,
ConfigParseOptions.defaults().setAllowMissing(false))
for (renderOptions <- optionsCombos) {
@@ -1134,7 +1131,7 @@ class ConfigTest extends TestUtils {
if (renderOptions.getJson() && !(renderOptions.getComments() || renderOptions.getOriginComments())) {
// should get valid JSON if we don't have comments and are resolved
val json = try {
- ConfigFactory.parseString(resolvedRender, ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON));
+ ConfigFactory.parseString(resolvedRender, ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
} catch {
case e: Exception =>
System.err.println("resolvedRender is not valid json: " + resolvedRender)
@@ -1269,7 +1266,7 @@ class ConfigTest extends TestUtils {
}
private def runFallbackTest(expected: String, source: String,
- allowUnresolved: Boolean, resolvers: ConfigResolver*) = {
+ allowUnresolved: Boolean, resolvers: ConfigResolver*): Unit = {
val unresolved = ConfigFactory.parseString(source)
var options = ConfigResolveOptions.defaults().setAllowUnresolved(allowUnresolved)
for (resolver <- resolvers)
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
index db593f1de..ca17e8a98 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
@@ -140,7 +140,7 @@ class ConfigValueTest extends TestUtils {
"_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_10200000025050000001906" +
"0000000D000B_f_a_k_e_ _o_r_i_g_i_n090000000100010400000001000103000000010001_x"
- val a = nullValue()
+ val a = nullValue
val b = checkSerializable(expectedSerialization, a)
assertNull("b is null", b.unwrapped)
}
@@ -424,11 +424,11 @@ class ConfigValueTest extends TestUtils {
longValue(11).toString()
doubleValue(3.14).toString()
stringValue("hi").toString()
- nullValue().toString()
+ nullValue.toString()
boolValue(true).toString()
val emptyObj = SimpleConfigObject.empty()
emptyObj.toString()
- (new SimpleConfigList(fakeOrigin(), Collections.emptyList[AbstractConfigValue]())).toString()
+ new SimpleConfigList(fakeOrigin(), Collections.emptyList[AbstractConfigValue]()).toString()
subst("a").toString()
substInString("b").toString()
val dm = new ConfigDelayedMerge(fakeOrigin(), List[AbstractConfigValue](subst("a"), subst("b")).asJava)
@@ -499,7 +499,7 @@ class ConfigValueTest extends TestUtils {
val l: ConfigList = new SimpleConfigList(fakeOrigin(),
scalaSeq.asJava)
- assertEquals(scalaSeq(0), l.get(0))
+ assertEquals(scalaSeq.head, l.get(0))
assertEquals(scalaSeq(1), l.get(1))
assertEquals(scalaSeq(2), l.get(2))
@@ -510,7 +510,7 @@ class ConfigValueTest extends TestUtils {
assertEquals(1, l.indexOf(scalaSeq(1)))
- assertFalse(l.isEmpty());
+ assertFalse(l.isEmpty())
assertEquals(scalaSeq, l.iterator().asScala.toSeq)
@@ -611,12 +611,12 @@ class ConfigValueTest extends TestUtils {
val obj = parseConfig("{ a : " + a + ", b : " + b + ", c : " + c + ", d : " + d + "}")
assertEquals(Seq(a, b, c, d),
- Seq("a", "b", "c", "d") map { obj.getString(_) })
+ Seq("a", "b", "c", "d") map { obj.getString })
// make sure it still works if we're doing concatenation
val obj2 = parseConfig("{ a : xx " + a + " yy, b : xx " + b + " yy, c : xx " + c + " yy, d : xx " + d + " yy}")
assertEquals(Seq(a, b, c, d) map { "xx " + _ + " yy" },
- Seq("a", "b", "c", "d") map { obj2.getString(_) })
+ Seq("a", "b", "c", "d") map { obj2.getString })
}
@Test
@@ -625,25 +625,25 @@ class ConfigValueTest extends TestUtils {
val values = new java.util.HashMap[String, AbstractConfigValue]()
if (!empty)
values.put("hello", intValue(37))
- new SimpleConfigObject(SimpleConfigOrigin.newSimple(desc), values);
+ new SimpleConfigObject(SimpleConfigOrigin.newSimple(desc), values)
}
def m(values: AbstractConfigObject*) = {
AbstractConfigObject.mergeOrigins(values: _*).description()
}
// simplest case
- assertEquals("merge of a,b", m(o("a", false), o("b", false)))
+ assertEquals("merge of a,b", m(o("a", empty = false), o("b", empty = false)))
// combine duplicate "merge of"
- assertEquals("merge of a,x,y", m(o("a", false), o("merge of x,y", false)))
- assertEquals("merge of a,b,x,y", m(o("merge of a,b", false), o("merge of x,y", false)))
+ assertEquals("merge of a,x,y", m(o("a", empty = false), o("merge of x,y", empty = false)))
+ assertEquals("merge of a,b,x,y", m(o("merge of a,b", empty = false), o("merge of x,y", empty = false)))
// ignore empty objects
- assertEquals("a", m(o("foo", true), o("a", false)))
+ assertEquals("a", m(o("foo", empty = true), o("a", empty = false)))
// unless they are all empty, pick the first one
- assertEquals("foo", m(o("foo", true), o("a", true)))
+ assertEquals("foo", m(o("foo", empty = true), o("a", empty = true)))
// merge just one
- assertEquals("foo", m(o("foo", false)))
+ assertEquals("foo", m(o("foo", empty = false)))
// merge three
- assertEquals("merge of a,b,c", m(o("a", false), o("b", false), o("c", false)))
+ assertEquals("merge of a,b,c", m(o("a", empty = false), o("b", empty = false), o("c", empty = false)))
}
@Test
@@ -661,7 +661,7 @@ class ConfigValueTest extends TestUtils {
assertTrue(obj.hasPath("b"))
// hasPath() is false for null values but containsKey is true
- assertEquals(nullValue(), obj.root.get("a"))
+ assertEquals(nullValue, obj.root.get("a"))
assertTrue(obj.root.containsKey("a"))
assertFalse(obj.hasPath("a"))
@@ -729,7 +729,7 @@ class ConfigValueTest extends TestUtils {
assertEquals(-1, noFilename.lineNumber())
assertEquals("foo: 3", filenameWithLine.description())
- assertEquals("bar: 4", noFilenameWithLine.description());
+ assertEquals("bar: 4", noFilenameWithLine.description())
assertEquals(3, filenameWithLine.lineNumber())
assertEquals(4, noFilenameWithLine.lineNumber())
@@ -944,10 +944,10 @@ class ConfigValueTest extends TestUtils {
})
def top(v: SimpleConfigList) = v.origin
def middle(v: SimpleConfigList) = v.get(0).origin
- def bottom(v: SimpleConfigList) = if (v.get(0).isInstanceOf[ConfigList])
- Some(v.get(0).asInstanceOf[ConfigList].get(0).origin)
- else
- None
+ def bottom(v: SimpleConfigList) = v.get(0) match {
+ case list: ConfigList => Some(list.get(0).origin)
+ case _ => None
+ }
//System.err.println("values=\n " + values.map(v => top(v).description + ", " + middle(v).description + ", " + bottom(v).map(_.description)).mkString("\n "))
for (v <- values) {
diff --git a/config/src/test/scala/com/typesafe/config/impl/EquivalentsTest.scala b/config/src/test/scala/com/typesafe/config/impl/EquivalentsTest.scala
index 3dd6d9938..62176cfe2 100644
--- a/config/src/test/scala/com/typesafe/config/impl/EquivalentsTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/EquivalentsTest.scala
@@ -63,7 +63,7 @@ class EquivalentsTest extends TestUtils {
val (originals, others) = files.partition({ f => f.getName().startsWith("original.") })
if (originals.isEmpty)
throw new RuntimeException("Need a file named 'original' in " + equiv.getPath())
- if (originals.size > 1)
+ if (originals.length > 1)
throw new RuntimeException("Multiple 'original' files in " + equiv.getPath() + ": " + originals)
val original = parse(originals(0))
diff --git a/config/src/test/scala/com/typesafe/config/impl/HttpTest.scala b/config/src/test/scala/com/typesafe/config/impl/HttpTest.scala
index 4cd56f064..bc8cb7e59 100644
--- a/config/src/test/scala/com/typesafe/config/impl/HttpTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/HttpTest.scala
@@ -92,7 +92,7 @@ object HttpTest {
private var server: Option[ToyHttp] = None
- def port = server.map(_.port).getOrElse(throw new Exception("http server isn't running"))
+ def port: Int = server.map(_.port).getOrElse(throw new Exception("http server isn't running"))
def baseUrl = s"http://127.0.0.1:$port"
private def handleThreeTypes(request: Request, json: String, props: String, hocon: String): Response = {
diff --git a/config/src/test/scala/com/typesafe/config/impl/JsonTest.scala b/config/src/test/scala/com/typesafe/config/impl/JsonTest.scala
index 6ba421f74..c9a2a1170 100644
--- a/config/src/test/scala/com/typesafe/config/impl/JsonTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/JsonTest.scala
@@ -3,29 +3,28 @@
*/
package com.typesafe.config.impl
-import org.junit.Assert._
-import org.junit._
-import net.liftweb.{ json => lift }
import java.io.Reader
-import java.io.StringReader
+import java.util
+
import com.typesafe.config._
-import java.util.HashMap
-import java.util.Collections
+import net.liftweb.{ json => lift }
+import org.junit.Assert._
+import org.junit._
class JsonTest extends TestUtils {
def parse(s: String): ConfigValue = {
val options = ConfigParseOptions.defaults().
setOriginDescription("test json string").
- setSyntax(ConfigSyntax.JSON);
- Parseable.newString(s, options).parseValue();
+ setSyntax(ConfigSyntax.JSON)
+ Parseable.newString(s, options).parseValue()
}
def parseAsConf(s: String): ConfigValue = {
val options = ConfigParseOptions.defaults().
setOriginDescription("test conf string").
- setSyntax(ConfigSyntax.CONF);
- Parseable.newString(s, options).parseValue();
+ setSyntax(ConfigSyntax.CONF)
+ Parseable.newString(s, options).parseValue()
}
private[this] def toLift(value: ConfigValue): lift.JValue = {
@@ -56,13 +55,11 @@ class JsonTest extends TestUtils {
liftValue match {
case lift.JObject(fields) =>
- val m = new HashMap[String, AbstractConfigValue]()
+ val m = new util.HashMap[String, AbstractConfigValue]()
fields.foreach({ field => m.put(field.name, fromLift(field.value)) })
new SimpleConfigObject(fakeOrigin(), m)
case lift.JArray(values) =>
- new SimpleConfigList(fakeOrigin(), values.map(fromLift(_)).asJava)
- case lift.JField(name, value) =>
- throw new IllegalStateException("either JField was a toplevel from lift-json or this function is buggy")
+ new SimpleConfigList(fakeOrigin(), values.map(fromLift).asJava)
case lift.JInt(i) =>
if (i.isValidInt) intValue(i.intValue) else longValue(i.longValue)
case lift.JBool(b) =>
@@ -147,7 +144,7 @@ class JsonTest extends TestUtils {
var tested = 0
// be sure we do the same thing as Lift when we build our JSON "DOM"
- for (valid <- whitespaceVariations(validJson, true)) {
+ for (valid <- whitespaceVariations(validJson, validInLift = true)) {
val liftAST = if (valid.liftBehaviorUnexpected) {
SimpleConfigObject.empty()
} else {
diff --git a/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala b/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala
index 70182df54..3ded66625 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ParseableReaderTest.scala
@@ -2,29 +2,29 @@ package com.typesafe.config.impl
import java.io.InputStreamReader
-import com.typesafe.config.{ConfigException, ConfigFactory, ConfigParseOptions}
+import com.typesafe.config.{ ConfigException, ConfigFactory, ConfigParseOptions }
import org.hamcrest.CoreMatchers.containsString
-import org.junit.Assert.{assertEquals, assertThat}
+import org.junit.Assert.{ assertEquals, assertThat }
import org.junit.Test
class ParseableReaderTest extends TestUtils {
- @Test
- def parse(): Unit = {
- val filename = "/test01.properties"
- val configInput = new InputStreamReader(getClass.getResourceAsStream(filename))
- val config = ConfigFactory.parseReader(configInput, ConfigParseOptions.defaults()
- .setSyntaxFromFilename(filename))
- assertEquals("hello^^", config.getString("fromProps.specialChars"))
- }
+ @Test
+ def parse(): Unit = {
+ val filename = "/test01.properties"
+ val configInput = new InputStreamReader(getClass.getResourceAsStream(filename))
+ val config = ConfigFactory.parseReader(configInput, ConfigParseOptions.defaults()
+ .setSyntaxFromFilename(filename))
+ assertEquals("hello^^", config.getString("fromProps.specialChars"))
+ }
- @Test
- def parseIncorrectFormat(): Unit = {
- val filename = "/test01.properties"
- val configInput = new InputStreamReader(getClass.getResourceAsStream(filename))
- val e = intercept[ConfigException.Parse] {
- ConfigFactory.parseReader(configInput)
+ @Test
+ def parseIncorrectFormat(): Unit = {
+ val filename = "/test01.properties"
+ val configInput = new InputStreamReader(getClass.getResourceAsStream(filename))
+ val e = intercept[ConfigException.Parse] {
+ ConfigFactory.parseReader(configInput)
+ }
+ assertThat(e.getMessage, containsString("Expecting end of input or a comma, got '^'"))
}
- assertThat(e.getMessage, containsString("Expecting end of input or a comma, got '^'"))
- }
}
diff --git a/config/src/test/scala/com/typesafe/config/impl/PathTest.scala b/config/src/test/scala/com/typesafe/config/impl/PathTest.scala
index 20a4d626c..9c53a9303 100644
--- a/config/src/test/scala/com/typesafe/config/impl/PathTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/PathTest.scala
@@ -15,13 +15,13 @@ class PathTest extends TestUtils {
// note: foo.bar is a single key here
val a = Path.newKey("foo.bar")
// check that newKey worked
- assertEquals(path("foo.bar"), a);
+ assertEquals(path("foo.bar"), a)
val sameAsA = Path.newKey("foo.bar")
val differentKey = Path.newKey("hello")
// here foo.bar is two elements
val twoElements = Path.newPath("foo.bar")
// check that newPath worked
- assertEquals(path("foo", "bar"), twoElements);
+ assertEquals(path("foo", "bar"), twoElements)
val sameAsTwoElements = Path.newPath("foo.bar")
checkEqualObjects(a, a)
diff --git a/config/src/test/scala/com/typesafe/config/impl/PropertiesTest.scala b/config/src/test/scala/com/typesafe/config/impl/PropertiesTest.scala
index 75cfe0fec..b20278e47 100644
--- a/config/src/test/scala/com/typesafe/config/impl/PropertiesTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/PropertiesTest.scala
@@ -108,7 +108,7 @@ class PropertiesTest extends TestUtils {
val conf = ConfigFactory.parseProperties(props, ConfigParseOptions.defaults())
val reference = ConfigFactory.parseString("{ a : [0,1,2,3,4] }")
- assertEquals(Seq(0, 1, 2, 3, 4), conf.getIntList("a").asScala.toSeq)
+ assertEquals(Seq(0, 1, 2, 3, 4), conf.getIntList("a").asScala)
conf.checkValid(reference)
}
diff --git a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
index 8b6787d1d..d33e215fe 100644
--- a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
@@ -574,7 +574,7 @@ abstract trait TestUtils {
protected def intValue(i: Int) = new ConfigInt(fakeOrigin(), i, null)
protected def longValue(l: Long) = new ConfigLong(fakeOrigin(), l, null)
protected def boolValue(b: Boolean) = new ConfigBoolean(fakeOrigin(), b)
- protected def nullValue() = new ConfigNull(fakeOrigin())
+ protected def nullValue = new ConfigNull(fakeOrigin())
protected def stringValue(s: String) = new ConfigString.Quoted(fakeOrigin(), s)
protected def doubleValue(d: Double) = new ConfigDouble(fakeOrigin(), d, null)
diff --git a/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala b/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala
index ac7a8ac39..79750bc83 100644
--- a/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/TokenizerTest.scala
@@ -202,8 +202,8 @@ class TokenizerTest extends TestUtils {
for (t <- invalidTests) {
val tokenized = tokenizeAsList(t)
- val maybeProblem = tokenized.find(Tokens.isProblem(_))
- assertTrue(s"expected failure for <$t> but got ${t}", maybeProblem.isDefined)
+ val maybeProblem = tokenized.find(Tokens.isProblem)
+ assertTrue(s"expected failure for <$t> but got $t", maybeProblem.isDefined)
}
}
@@ -247,9 +247,9 @@ class TokenizerTest extends TestUtils {
abstract class NumberTest(val s: String, val result: Token)
case class LongTest(override val s: String, override val result: Token) extends NumberTest(s, result)
case class DoubleTest(override val s: String, override val result: Token) extends NumberTest(s, result)
- implicit def pair2inttest(pair: (String, Int)) = LongTest(pair._1, tokenLong(pair._2))
- implicit def pair2longtest(pair: (String, Long)) = LongTest(pair._1, tokenLong(pair._2))
- implicit def pair2doubletest(pair: (String, Double)) = DoubleTest(pair._1, tokenDouble(pair._2))
+ implicit def pair2inttest(pair: (String, Int)): LongTest = LongTest(pair._1, tokenLong(pair._2))
+ implicit def pair2longtest(pair: (String, Long)): LongTest = LongTest(pair._1, tokenLong(pair._2))
+ implicit def pair2doubletest(pair: (String, Double)): DoubleTest = DoubleTest(pair._1, tokenDouble(pair._2))
val tests = List[NumberTest](("1", 1),
("1.2", 1.2),
@@ -302,7 +302,7 @@ class TokenizerTest extends TestUtils {
for (invalid <- "+`^?!@*&\\") {
val tokenized = tokenizeAsList(invalid.toString)
assertEquals(3, tokenized.size)
- assertEquals(Tokens.START, tokenized(0))
+ assertEquals(Tokens.START, tokenized.head)
assertEquals(Tokens.END, tokenized(2))
val problem = tokenized(1)
assertTrue("reserved char is a problem", Tokens.isProblem(problem))
diff --git a/config/src/test/scala/com/typesafe/config/impl/ToyHttp.scala b/config/src/test/scala/com/typesafe/config/impl/ToyHttp.scala
index 0bf39c2c0..70214b435 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ToyHttp.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ToyHttp.scala
@@ -25,10 +25,7 @@ final class ToyHttp(handler: ToyHttp.Request => ToyHttp.Response) {
private final val serverSocket = new ServerSocket()
serverSocket.bind(new InetSocketAddress("127.0.0.1", 0))
final val port = serverSocket.getLocalPort
- private final val thread = new Thread(new Runnable() {
- override def run() =
- mainLoop();
- })
+ private final val thread = new Thread(() => mainLoop())
thread.setDaemon(true)
thread.setName("ToyHttp")
@@ -118,8 +115,8 @@ final class ToyHttp(handler: ToyHttp.Request => ToyHttp.Response) {
//val stuff = new java.io.ByteArrayOutputStream
//val writer = new PrintWriter(new OutputStreamWriter(stuff, StandardCharsets.UTF_8))
val writer = new PrintWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))
- val dateFormat = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
- dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+ val dateFormat = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US)
+ dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"))
writer.append(s"HTTP/1.1 ${response.code} ${codeText(response.code)}\r\n")
writer.append(s"Date: ${dateFormat.format(new Date)}\r\n")
diff --git a/config/src/test/scala/com/typesafe/config/impl/UnitParserTest.scala b/config/src/test/scala/com/typesafe/config/impl/UnitParserTest.scala
index a06a40c19..0a7f7e3e3 100644
--- a/config/src/test/scala/com/typesafe/config/impl/UnitParserTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/UnitParserTest.scala
@@ -44,7 +44,7 @@ class UnitParserTest extends TestUtils {
}
@Test
- def parsePeriod() = {
+ def parsePeriod(): Unit = {
val oneYears = List(
"1y", "1 y", "1year", "1 years", " 1y ", " 1 y ",
"365", "365d", "365 d", "365 days", " 365 days ", "365day",
@@ -157,7 +157,7 @@ class UnitParserTest extends TestUtils {
@Test
def parseHugeMemorySizes(): Unit = {
def parseMem(s: String): Long = SimpleConfig.parseBytes(s, fakeOrigin(), "test")
- def assertOutOfRange(s: String) = {
+ def assertOutOfRange(s: String): Unit = {
val fail = intercept[ConfigException.BadValue] {
parseMem(s)
}
diff --git a/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala b/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala
index bccbaa476..6d0bb160c 100644
--- a/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/UtilTest.scala
@@ -58,7 +58,7 @@ class UtilTest extends TestUtils {
assertTrue(ConfigImplUtil.equalsHandlingNull("", ""))
}
- val lotsOfStrings = (invalidJson ++ validConf).map(_.test)
+ val lotsOfStrings: List[String] = (invalidJson ++ validConf).map(_.test)
private def roundtripJson(s: String) {
val rendered = ConfigImplUtil.renderJsonString(s)
diff --git a/examples/scala/complex-app/src/main/scala/ComplexApp.scala b/examples/scala/complex-app/src/main/scala/ComplexApp.scala
index 507da8cb1..68d530303 100644
--- a/examples/scala/complex-app/src/main/scala/ComplexApp.scala
+++ b/examples/scala/complex-app/src/main/scala/ComplexApp.scala
@@ -35,7 +35,7 @@ object ComplexApp extends App {
//////////
// "config2" shows how to configure a library with a custom settings subtree
- val config2 = ConfigFactory.load("complex2");
+ val config2 = ConfigFactory.load("complex2")
// use the config ourselves
println("config2, complex-app.something=" + config2.getString("complex-app.something"))
diff --git a/examples/scala/simple-lib/src/main/scala/simplelib/SimpleLib.scala b/examples/scala/simple-lib/src/main/scala/simplelib/SimpleLib.scala
index 06b03c0a5..5c02c0920 100644
--- a/examples/scala/simple-lib/src/main/scala/simplelib/SimpleLib.scala
+++ b/examples/scala/simple-lib/src/main/scala/simplelib/SimpleLib.scala
@@ -40,9 +40,9 @@ class SimpleLibSettings(config: Config) {
// note that these fields are NOT lazy, because if we're going to
// get any exceptions, we want to get them on startup.
- val foo = config.getString("simple-lib.foo")
- val hello = config.getString("simple-lib.hello")
- val whatever = config.getString("simple-lib.whatever")
+ val foo: String = config.getString("simple-lib.foo")
+ val hello: String = config.getString("simple-lib.hello")
+ val whatever: String = config.getString("simple-lib.whatever")
}
// This is a different way to do SimpleLibContext, using the
diff --git a/project/linksource.scala b/project/linksource.scala
index 70f49fc0d..7e98040fb 100644
--- a/project/linksource.scala
+++ b/project/linksource.scala
@@ -1,4 +1,4 @@
-import sbt._
+import sbt.{Def, _}
import Keys._
import plugins.JvmPlugin
@@ -12,7 +12,7 @@ object LinkSourcePlugin extends AutoPlugin {
override def trigger = allRequirements
override def requires = JvmPlugin
- override lazy val projectSettings = Seq(
+ override lazy val projectSettings: Seq[Def.Setting[_ >: Option[String] with Task[Seq[String]] with Task[File] <: Product]] = Seq(
javadocSourceBaseUrl := None,
javacOptions in (Compile, doc) := {
val old = (javacOptions in doc).value
From 86d9ea0d5b1a909095838de8e3aa33f287fbe3e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Mela?=
Date: Tue, 10 Jul 2018 20:58:41 +0200
Subject: [PATCH 44/83] Fixed support for keys that are all digits but longer
than an int.
Previously such config keys would still be parsed with
`Integer#parseInt` for the sake of sorting, resulting in a `NumberFormatException`.
Now the keys consisting of digits only are parsed to a `BigInteger` and
compared as such.
This addresses the following issues:
https://github.com/lightbend/config/issues/604
https://github.com/lightbend/config/issues/541
---
.../config/impl/SimpleConfigObject.java | 8 ++--
config/src/test/resources/test12.conf | 43 +++++++++++++++++++
config/src/test/scala/Rendering.scala | 1 +
.../config/impl/ConfigValueTest.scala | 4 +-
4 files changed, 50 insertions(+), 6 deletions(-)
create mode 100644 config/src/test/resources/test12.conf
diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfigObject.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfigObject.java
index cf5f5ea07..ef69c6885 100644
--- a/config/src/main/java/com/typesafe/config/impl/SimpleConfigObject.java
+++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfigObject.java
@@ -5,6 +5,7 @@
import java.io.ObjectStreamException;
import java.io.Serializable;
+import java.math.BigInteger;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
@@ -426,15 +427,14 @@ private static boolean isAllDigits(String s) {
int length = s.length();
// empty string doesn't count as a number
+ // string longer than "max number of digits in a long" cannot be parsed as a long
if (length == 0)
return false;
for (int i = 0; i < length; ++i) {
char c = s.charAt(i);
- if (Character.isDigit(c))
- continue;
- else
+ if (!Character.isDigit(c))
return false;
}
return true;
@@ -449,7 +449,7 @@ public int compare(String a, String b) {
boolean aDigits = isAllDigits(a);
boolean bDigits = isAllDigits(b);
if (aDigits && bDigits) {
- return Integer.compare(Integer.parseInt(a), Integer.parseInt(b));
+ return new BigInteger(a).compareTo(new BigInteger(b));
} else if (aDigits) {
return -1;
} else if (bDigits) {
diff --git a/config/src/test/resources/test12.conf b/config/src/test/resources/test12.conf
new file mode 100644
index 000000000..b7aff622b
--- /dev/null
+++ b/config/src/test/resources/test12.conf
@@ -0,0 +1,43 @@
+// this checks sorting map keys, where keys that look like numbers are treated differently
+// specifically tests very long numbers which fit neither in an Integer nor in a Long
+
+"10" = "42"
+sth = 42
+"1" = "42"
+"12" = "42"
+"123" = "42"
+"1234" = "42"
+"12345" = "42"
+"123456" = "42"
+"1234567" = "42"
+"12345678" = "42"
+"123456789" = "42"
+"1234567890" = "42"
+"12345678901" = "42"
+"123456789012" = "42"
+"1234567890123" = "42"
+"12345678901234" = "42"
+"123456789012345" = "42"
+"1234567890123456" = "42"
+"12345678901234567" = "42"
+"123456789012345678" = "42"
+"1234567890123456789" = "42"
+"12345678901234567891" = "42"
+"123456789012345678912" = "42"
+"1234567890123456789123" = "42"
+"12345678901234567891234" = "42"
+"123456789012345678912345" = "42"
+"1234567890123456789123456" = "42"
+"12345678901234567891234567" = "42"
+"123456789012345678912345678" = "42"
+"1234567890123456789123456789" = "42"
+"12345678901234567891234567890" = "42"
+"123456789012345678912345678901" = "42"
+"1234567890123456789123456789012" = "42"
+"12345678901234567891234567890123" = "42"
+"123456789012345678912345678901234" = "42"
+"1234567890123456789123456789012345" = "42"
+"12345678901234567891234567890123456" = "42"
+"123456789012345678912345678901234567" = "42"
+"1234567890123456789123456789012345678" = "42"
+"12345678901234567891234567890123456789" = "42"
\ No newline at end of file
diff --git a/config/src/test/scala/Rendering.scala b/config/src/test/scala/Rendering.scala
index 0d8be469e..e1ca3cf6d 100644
--- a/config/src/test/scala/Rendering.scala
+++ b/config/src/test/scala/Rendering.scala
@@ -33,6 +33,7 @@ object RenderExample extends App {
render("test01")
render("test06")
render("test05")
+ render("test12")
}
object RenderOptions extends App {
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
index db593f1de..de97288c3 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
@@ -982,8 +982,8 @@ class ConfigValueTest extends TestUtils {
@Test
def renderSorting(): Unit = {
- val config = parseConfig("""0=a,1=b,2=c,3=d,10=e,20=f,30=g""")
+ val config = parseConfig("""0=a,1=b,2=c,999999999999999999999999999999999999999999999=0,3=d,10=e,20a=f,20=g,30=h""")
val rendered = config.root.render(ConfigRenderOptions.concise())
- assertEquals("""{"0":"a","1":"b","2":"c","3":"d","10":"e","20":"f","30":"g"}""", rendered)
+ assertEquals("""{"0":"a","1":"b","2":"c","3":"d","10":"e","20":"g","30":"h","999999999999999999999999999999999999999999999":0,"20a":"f"}""", rendered)
}
}
From d468cd5ea43d3c37510ddf2a3a5a5e6eb3b8380c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martynas=20Mickevi=C4=8Dius?=
Date: Thu, 24 Jan 2019 09:54:41 +0100
Subject: [PATCH 45/83] Use AdoptOpenJDK
---
.travis.yml | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 9c62ad817..df74bfb98 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,19 +1,24 @@
# use Docker-based container (instead of OpenVZ)
sudo: false
-cache:
- directories:
- - $HOME/.ivy2/cache
- - $HOME/.sbt/boot
-
language: scala
-jdk:
- - oraclejdk8
+before_install:
+ # using jabba for custom jdk management
+ - curl -sL https://raw.githubusercontent.com/shyiko/jabba/0.11.2/install.sh | bash && . ~/.jabba/jabba.sh
+ - jabba install adopt@1.8.202-08
+ - java -version
script:
- sbt ++$TRAVIS_SCALA_VERSION test doc
+before_cache:
# Remove to avoid unnecessary cache updates
- find $HOME/.sbt -name "*.lock" -delete
- find $HOME/.ivy2 -name "ivydata-*.properties" -delete
+
+cache:
+ directories:
+ - $HOME/.ivy2/cache
+ - $HOME/.sbt/boot
+ - $HOME/.jabba/jdk
From 7e268070cd8f44f95f3a7739423acb845d115690 Mon Sep 17 00:00:00 2001
From: Dale Wijnand
Date: Mon, 28 Jan 2019 15:44:58 +0000
Subject: [PATCH 46/83] Drop note on Akka 2.0/Play 2.0
I initially misread the note to mean Akka/Play 2.x.
Seeing as Akka 2.0 and Play 2.0 is close to 7 years ago, we can lose the note now?
* https://github.com/akka/akka/releases/tag/v2.0
* https://github.com/playframework/playframework/releases/tag/2.0
---
HOCON.md | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/HOCON.md b/HOCON.md
index 6e0818c05..9f8bd837d 100644
--- a/HOCON.md
+++ b/HOCON.md
@@ -317,11 +317,6 @@ String value concatenation is allowed in field keys, in addition
to field values and array elements. Objects and arrays do not make
sense as field keys.
-Note: Akka 2.0 (and thus Play 2.0) contains an embedded
-implementation of the config lib which does not support array and
-object value concatenation; it only supports string value
-concatenation.
-
#### String value concatenation
String value concatenation is the trick that makes unquoted
@@ -739,9 +734,6 @@ optional (`${?a}` not `${a}`), which allows `a += b` to be the
first mention of `a` in the file (it is not necessary to have `a =
[]` first).
-Note: Akka 2.0 (and thus Play 2.0) contains an embedded
-implementation of the config lib which does not support `+=`.
-
#### Examples of Self-Referential Substitutions
In isolation (with no merges involved), a self-referential field
@@ -959,11 +951,6 @@ word `"include"`, only unquoted `include` is special:
{ "include" : 42 }
-Note: Akka 2.0 (and thus Play 2.0) contains an embedded
-implementation of the config lib which does not support the
-`url()`/`file()`/`classpath()` syntax. Only the heuristic `include
-"foo"` syntax is supported in that version.
-
#### Include semantics: merging
An _including file_ contains the include statement and an
From 7f8e587f72a700a4eb2593ae8ad30973c69fa997 Mon Sep 17 00:00:00 2001
From: Eric Richardson
Date: Thu, 14 Feb 2019 12:15:09 -0500
Subject: [PATCH 47/83] Add new Scala port to README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index ea89fd62f..ff594afeb 100644
--- a/README.md
+++ b/README.md
@@ -867,6 +867,7 @@ format.
#### Scala port
* SHocon https://github.com/unicredit/shocon (work with both Scala and Scala.Js)
+ * sconfig https://github.com/ekrich/sconfig
#### Ruby port
From d56d5906669c6cd4885ecbdd2d1c9daef8d62b61 Mon Sep 17 00:00:00 2001
From: Eric Richardson
Date: Thu, 14 Feb 2019 15:48:15 -0500
Subject: [PATCH 48/83] Update Shocon entry
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index ff594afeb..28d51af89 100644
--- a/README.md
+++ b/README.md
@@ -866,7 +866,7 @@ format.
#### Scala port
- * SHocon https://github.com/unicredit/shocon (work with both Scala and Scala.Js)
+ * SHocon https://github.com/akka-js/shocon (Supports Scala.js and Scala Native)
* sconfig https://github.com/ekrich/sconfig
#### Ruby port
From 1622208ebd0ed2ea48261c49ba194f9bb2db5b7f Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Wed, 27 Feb 2019 12:37:37 +0000
Subject: [PATCH 49/83] Add a config strategy to load from environment
variables first.
---
config/checkstyle-config.xml | 2 +-
config/checkstyle-suppressions.xml | 2 +-
.../config/EnvFirstConfigLoadingStrategy.java | 79 +++++++++++++++++++
.../com/typesafe/config/impl/ConfigTest.scala | 47 +++++++++++
.../typesafe/config/impl/PublicApiTest.scala | 29 +++++++
5 files changed, 157 insertions(+), 2 deletions(-)
create mode 100644 config/src/main/java/com/typesafe/config/EnvFirstConfigLoadingStrategy.java
diff --git a/config/checkstyle-config.xml b/config/checkstyle-config.xml
index b5b71d2b6..0fc2c197a 100644
--- a/config/checkstyle-config.xml
+++ b/config/checkstyle-config.xml
@@ -1,7 +1,7 @@
+ "https://checkstyle.org/dtds/configuration_1_3.dtd">
diff --git a/config/checkstyle-suppressions.xml b/config/checkstyle-suppressions.xml
index 21fb8e51e..6fa3fdc00 100644
--- a/config/checkstyle-suppressions.xml
+++ b/config/checkstyle-suppressions.xml
@@ -1,6 +1,6 @@
+ "https://checkstyle.org/dtds/configuration_1_3.dtd">
+ * Environment variables are mangled in the following way after stripping the prefix:
+ *
+ *
+ *
Env Var
+ *
Config
+ *
+ *
+ *
_ [1 underscore]
+ *
. [dot]
+ *
+ *
+ *
__ [2 underscore]
+ *
- [dash]
+ *
+ *
+ *
___ [3 underscore]
+ *
_ [underscore]
+ *
+ *
+ *
+ *
+ * A variable like: {@code CONFIG_a_b__c___d}
+ * is translated to a config key: {@code a.b-c_d}
+ *
+ *
+ * The prefix may be altered by defining the VM property {@code config.env_var_prefix}
+ */
+public class EnvFirstConfigLoadingStrategy extends DefaultConfigLoadingStrategy {
+
+ protected static Map env = new HashMap(System.getenv());
+
+ @Override
+ public Config parseApplicationConfig(ConfigParseOptions parseOptions) {
+ String envVarPrefix = System.getProperty("config.env_var_prefix");
+ if (envVarPrefix == null) // fallback to default
+ envVarPrefix = "CONFIG_";
+
+ Map defaultsFromEnv = new HashMap();
+ for (String key : env.keySet()) {
+ if (key.startsWith(envVarPrefix)) {
+ StringBuilder builder = new StringBuilder();
+
+ String strippedPrefix = key.substring(envVarPrefix.length(), key.length());
+
+ int underscores = 0;
+ for (char c : strippedPrefix.toCharArray()) {
+ if (c == '_') {
+ underscores++;
+ } else {
+ switch (underscores) {
+ case 1: builder.append('.');
+ break;
+ case 2: builder.append('-');
+ break;
+ case 3: builder.append('_');
+ break;
+ }
+ underscores = 0;
+ builder.append(c);
+ }
+ }
+
+ String propertyKey = builder.toString();
+ defaultsFromEnv.put(propertyKey, env.get(key));
+ }
+ }
+
+ return ConfigFactory.parseMap(defaultsFromEnv).withFallback(super.parseApplicationConfig(parseOptions));
+ }
+}
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 1bf031ba3..f5084c79d 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -1090,6 +1090,53 @@ class ConfigTest extends TestUtils {
assertEquals(10, resolved.getInt("bar.nested.a.q"))
}
+ @Test
+ def testLoadWithEnvSubstitutions() {
+ TestEnvFirstStrategy.putEnvVar("CONFIG_42___a", "1")
+ TestEnvFirstStrategy.putEnvVar("CONFIG_a_b_c", "2")
+ TestEnvFirstStrategy.putEnvVar("CONFIG_a__c", "3")
+ TestEnvFirstStrategy.putEnvVar("CONFIG_a___c", "4")
+
+ TestEnvFirstStrategy.putEnvVar("CONFIG_akka_version", "foo")
+ TestEnvFirstStrategy.putEnvVar("CONFIG_akka_event__handler__dispatcher_max__pool__size", "10")
+
+ System.setProperty("config.strategy", classOf[EnvFirstConfigLoadingStrategy].getCanonicalName)
+
+ try {
+ val loader02 = new TestClassLoader(this.getClass().getClassLoader(),
+ Map("reference.conf" -> resourceFile("test02.conf").toURI.toURL()))
+
+ val loader04 = new TestClassLoader(this.getClass().getClassLoader(),
+ Map("reference.conf" -> resourceFile("test04.conf").toURI.toURL()))
+
+ val conf02 = withContextClassLoader(loader02) {
+ ConfigFactory.load()
+ }
+
+ val conf04 = withContextClassLoader(loader04) {
+ ConfigFactory.load()
+ }
+
+ assertEquals(1, conf02.getInt("42_a"))
+ assertEquals(2, conf02.getInt("a.b.c"))
+ assertEquals(3, conf02.getInt("a-c"))
+ assertEquals(4, conf02.getInt("a_c"))
+
+ assertEquals("foo", conf04.getString("akka.version"))
+ assertEquals(10, conf04.getInt("akka.event-handler-dispatcher.max-pool-size"))
+ } finally {
+ System.clearProperty("config.strategy")
+
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_42___a")
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_a_b_c")
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_a__c")
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_a___c")
+
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_akka_version")
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_akka_event__handler__dispatcher_max__pool__size")
+ }
+ }
+
@Test
def renderRoundTrip() {
val allBooleans = true :: false :: Nil
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 d25d43659..136ea690a 100644
--- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
@@ -653,6 +653,28 @@ class PublicApiTest extends TestUtils {
}
}
+ @Test
+ def supportsEnvFirstConfigLoadingStrategy(): Unit = {
+ assertEquals("config.strategy is not set", null, System.getProperty("config.strategy"))
+
+ TestEnvFirstStrategy.putEnvVar("CONFIG_a", "5")
+ System.setProperty("config.strategy", classOf[EnvFirstConfigLoadingStrategy].getCanonicalName)
+
+ try {
+ val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
+ Map("reference.conf" -> resourceFile("a_1.conf").toURI.toURL()))
+
+ val configA1 = withContextClassLoader(loaderA1) {
+ ConfigFactory.load()
+ }
+
+ assertEquals(5, configA1.getInt("a"))
+ } finally {
+ System.clearProperty("config.strategy")
+ TestEnvFirstStrategy.removeEnvVar("CONFIG_a")
+ }
+ }
+
@Test
def usesContextClassLoaderForApplicationConf() {
val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
@@ -1145,4 +1167,11 @@ object TestStrategy {
private var invocations = 0
def getIncovations() = invocations
def increment() = invocations += 1
+}
+
+object TestEnvFirstStrategy extends EnvFirstConfigLoadingStrategy {
+ def putEnvVar(key: String, value: String) =
+ EnvFirstConfigLoadingStrategy.env.put(key, value)
+ def removeEnvVar(key: String) =
+ EnvFirstConfigLoadingStrategy.env.remove(key)
}
\ No newline at end of file
From 7d7380fe040375bead3e3989649e030530f50d6c Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Wed, 27 Feb 2019 12:39:46 +0000
Subject: [PATCH 50/83] Fix suppressions doctype
---
config/checkstyle-suppressions.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/checkstyle-suppressions.xml b/config/checkstyle-suppressions.xml
index 6fa3fdc00..62d514067 100644
--- a/config/checkstyle-suppressions.xml
+++ b/config/checkstyle-suppressions.xml
@@ -1,6 +1,6 @@
+ "https://checkstyle.org/dtds/suppressions_1_1.dtd">
Date: Wed, 27 Feb 2019 12:41:15 +0000
Subject: [PATCH 51/83] Trailing blank line
---
.../src/test/scala/com/typesafe/config/impl/PublicApiTest.scala | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 136ea690a..5eed422ac 100644
--- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
@@ -1174,4 +1174,4 @@ object TestEnvFirstStrategy extends EnvFirstConfigLoadingStrategy {
EnvFirstConfigLoadingStrategy.env.put(key, value)
def removeEnvVar(key: String) =
EnvFirstConfigLoadingStrategy.env.remove(key)
-}
\ No newline at end of file
+}
From 8a14342ca5678b79d164726df92c06a5a7468b0c Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Mon, 4 Mar 2019 14:43:12 +0000
Subject: [PATCH 52/83] Env variables resolution moved to defaultOverrides
---
build.sbt | 12 ++-
.../com/typesafe/config/ConfigFactory.java | 59 +++++++++++++-
.../config/EnvFirstConfigLoadingStrategy.java | 79 -------------------
.../com/typesafe/config/impl/ConfigImpl.java | 52 ++++++++++++
.../com/typesafe/config/impl/ConfigTest.scala | 20 +----
.../typesafe/config/impl/PublicApiTest.scala | 25 ++----
6 files changed, 130 insertions(+), 117 deletions(-)
delete mode 100644 config/src/main/java/com/typesafe/config/EnvFirstConfigLoadingStrategy.java
diff --git a/build.sbt b/build.sbt
index 9d78b6aea..15260557a 100644
--- a/build.sbt
+++ b/build.sbt
@@ -85,7 +85,17 @@ lazy val configLib = Project("config", file("config"))
Test/ run / fork := true
//env vars for tests
- Test / envVars ++= Map("testList.0" -> "0", "testList.1" -> "1")
+ Test / envVars ++= Map("testList.0" -> "0",
+ "testList.1" -> "1",
+ "CONFIG_FORCE_b" -> "5",
+ "CONFIG_FORCE_testList_0" -> "10",
+ "CONFIG_FORCE_testList_1" -> "11",
+ "CONFIG_FORCE_42___a" -> "1",
+ "CONFIG_FORCE_a_b_c" -> "2",
+ "CONFIG_FORCE_a__c" -> "3",
+ "CONFIG_FORCE_a___c" -> "4",
+ "CONFIG_FORCE_akka_version" -> "foo",
+ "CONFIG_FORCE_akka_event__handler__dispatcher_max__pool__size" -> "10")
OsgiKeys.exportPackage := Seq("com.typesafe.config", "com.typesafe.config.impl")
publish := sys.error("use publishSigned instead of plain publish")
diff --git a/config/src/main/java/com/typesafe/config/ConfigFactory.java b/config/src/main/java/com/typesafe/config/ConfigFactory.java
index 86d995e36..8405520f5 100644
--- a/config/src/main/java/com/typesafe/config/ConfigFactory.java
+++ b/config/src/main/java/com/typesafe/config/ConfigFactory.java
@@ -36,6 +36,7 @@
*/
public final class ConfigFactory {
private static final String STRATEGY_PROPERTY_NAME = "config.strategy";
+ private static final String OVERRIDE_WITH_ENV_PROPERTY_NAME = "config.override_with_env_vars";
private ConfigFactory() {
}
@@ -383,7 +384,11 @@ public static Config defaultReference(ClassLoader loader) {
* @return the default override configuration
*/
public static Config defaultOverrides() {
- return systemProperties();
+ if (!getOverrideWithEnv()) {
+ return systemProperties();
+ } else {
+ return systemEnvironmentOverrides().withFallback(systemProperties());
+ }
}
/**
@@ -394,7 +399,7 @@ public static Config defaultOverrides() {
* @return the default override configuration
*/
public static Config defaultOverrides(ClassLoader loader) {
- return systemProperties();
+ return defaultOverrides();
}
/**
@@ -549,6 +554,50 @@ public static Config systemProperties() {
return ConfigImpl.systemPropertiesAsConfig();
}
+ /**
+ * Gets a Config containing the system's environment variables
+ * used to override configuration keys.
+ * Environment variables taken in considerations are starting with
+ * {@code CONFIG_FORCE_}
+ *
+ *
+ * Environment variables are mangled in the following way after stripping the prefix "CONFIG_FORCE_":
+ *
+ *
+ *
Env Var
+ *
Config
+ *
+ *
+ *
_ [1 underscore]
+ *
. [dot]
+ *
+ *
+ *
__ [2 underscore]
+ *
- [dash]
+ *
+ *
+ *
___ [3 underscore]
+ *
_ [underscore]
+ *
+ *
+ *
+ *
+ * A variable like: {@code CONFIG_FORCE_a_b__c___d}
+ * is translated to a config key: {@code a.b-c_d}
+ *
+ *
+ * This method can return a global immutable singleton, so it's preferred
+ * over parsing system properties yourself.
+ *
+ * {@link #defaultOverrides} will include the system system environment variables as
+ * overrides if `config.override_with_env_vars` is set to `true`.
+ *
+ * @return system environment variable overrides parsed into a Config
+ */
+ public static Config systemEnvironmentOverrides() {
+ return ConfigImpl.envVariablesOverridesAsConfig();
+ }
+
/**
* Gets a Config containing the system's environment variables.
* This method can return a global immutable singleton.
@@ -1063,4 +1112,10 @@ private static ConfigLoadingStrategy getConfigLoadingStrategy() {
return new DefaultConfigLoadingStrategy();
}
}
+
+ private static Boolean getOverrideWithEnv() {
+ String overrideWithEnv = System.getProperties().getProperty(OVERRIDE_WITH_ENV_PROPERTY_NAME);
+
+ return Boolean.parseBoolean(overrideWithEnv);
+ }
}
diff --git a/config/src/main/java/com/typesafe/config/EnvFirstConfigLoadingStrategy.java b/config/src/main/java/com/typesafe/config/EnvFirstConfigLoadingStrategy.java
deleted file mode 100644
index 0b0948035..000000000
--- a/config/src/main/java/com/typesafe/config/EnvFirstConfigLoadingStrategy.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.typesafe.config;
-
-import java.util.Map;
-import java.util.HashMap;
-
-/**
- * Environment variables first config loading strategy. Able to load environment variables first and fallback to {@link DefaultConfigLoadingStrategy}
- *
- *
- * Environment variables are mangled in the following way after stripping the prefix:
- *
- *
- *
Env Var
- *
Config
- *
- *
- *
_ [1 underscore]
- *
. [dot]
- *
- *
- *
__ [2 underscore]
- *
- [dash]
- *
- *
- *
___ [3 underscore]
- *
_ [underscore]
- *
- *
- *
- *
- * A variable like: {@code CONFIG_a_b__c___d}
- * is translated to a config key: {@code a.b-c_d}
- *
- *
- * The prefix may be altered by defining the VM property {@code config.env_var_prefix}
- */
-public class EnvFirstConfigLoadingStrategy extends DefaultConfigLoadingStrategy {
-
- protected static Map env = new HashMap(System.getenv());
-
- @Override
- public Config parseApplicationConfig(ConfigParseOptions parseOptions) {
- String envVarPrefix = System.getProperty("config.env_var_prefix");
- if (envVarPrefix == null) // fallback to default
- envVarPrefix = "CONFIG_";
-
- Map defaultsFromEnv = new HashMap();
- for (String key : env.keySet()) {
- if (key.startsWith(envVarPrefix)) {
- StringBuilder builder = new StringBuilder();
-
- String strippedPrefix = key.substring(envVarPrefix.length(), key.length());
-
- int underscores = 0;
- for (char c : strippedPrefix.toCharArray()) {
- if (c == '_') {
- underscores++;
- } else {
- switch (underscores) {
- case 1: builder.append('.');
- break;
- case 2: builder.append('-');
- break;
- case 3: builder.append('_');
- break;
- }
- underscores = 0;
- builder.append(c);
- }
- }
-
- String propertyKey = builder.toString();
- defaultsFromEnv.put(propertyKey, env.get(key));
- }
- }
-
- return ConfigFactory.parseMap(defaultsFromEnv).withFallback(super.parseApplicationConfig(parseOptions));
- }
-}
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 9cf49913b..f9057ede5 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
@@ -32,6 +32,7 @@
* For use only by the {@link com.typesafe.config} package.
*/
public class ConfigImpl {
+ private static final String ENV_VAR_OVERRIDE_PREFIX = "CONFIG_FORCE_";
private static class LoaderCache {
private Config currentSystemProperties;
@@ -360,6 +361,57 @@ public static void reloadEnvVariablesConfig() {
EnvVariablesHolder.envVariables = loadEnvVariables();
}
+ private static AbstractConfigObject loadEnvVariablesOverrides() {
+ Map env = new HashMap(System.getenv());
+ Map result = new HashMap(System.getenv());
+ for (String key : env.keySet()) {
+ if (key.startsWith(ENV_VAR_OVERRIDE_PREFIX)) {
+ StringBuilder builder = new StringBuilder();
+
+ String strippedPrefix = key.substring(ENV_VAR_OVERRIDE_PREFIX.length(), key.length());
+
+ int underscores = 0;
+ for (char c : strippedPrefix.toCharArray()) {
+ if (c == '_') {
+ underscores++;
+ } else {
+ switch (underscores) {
+ case 1: builder.append('.');
+ break;
+ case 2: builder.append('-');
+ break;
+ case 3: builder.append('_');
+ break;
+ }
+ underscores = 0;
+ builder.append(c);
+ }
+ }
+
+ String propertyKey = builder.toString();
+ result.put(propertyKey, env.get(key));
+ }
+ }
+
+ return PropertiesParser.fromStringMap(newSimpleOrigin("env variables overrides"), result);
+ }
+
+ private static class EnvVariablesOverridesHolder {
+ static volatile AbstractConfigObject envVariables = loadEnvVariablesOverrides();
+ }
+
+ static AbstractConfigObject envVariablesOverridesAsConfigObject() {
+ try {
+ return EnvVariablesOverridesHolder.envVariables;
+ } catch (ExceptionInInitializerError e) {
+ throw ConfigImplUtil.extractInitializerError(e);
+ }
+ }
+
+ public static Config envVariablesOverridesAsConfig() {
+ return envVariablesOverridesAsConfigObject().toConfig();
+ }
+
public static Config defaultReference(final ClassLoader loader) {
return computeCachedConfig(loader, "defaultReference", new Callable() {
@Override
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 f5084c79d..853aa249f 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -1092,15 +1092,7 @@ class ConfigTest extends TestUtils {
@Test
def testLoadWithEnvSubstitutions() {
- TestEnvFirstStrategy.putEnvVar("CONFIG_42___a", "1")
- TestEnvFirstStrategy.putEnvVar("CONFIG_a_b_c", "2")
- TestEnvFirstStrategy.putEnvVar("CONFIG_a__c", "3")
- TestEnvFirstStrategy.putEnvVar("CONFIG_a___c", "4")
-
- TestEnvFirstStrategy.putEnvVar("CONFIG_akka_version", "foo")
- TestEnvFirstStrategy.putEnvVar("CONFIG_akka_event__handler__dispatcher_max__pool__size", "10")
-
- System.setProperty("config.strategy", classOf[EnvFirstConfigLoadingStrategy].getCanonicalName)
+ System.setProperty("config.override_with_env_vars", "true")
try {
val loader02 = new TestClassLoader(this.getClass().getClassLoader(),
@@ -1125,15 +1117,7 @@ class ConfigTest extends TestUtils {
assertEquals("foo", conf04.getString("akka.version"))
assertEquals(10, conf04.getInt("akka.event-handler-dispatcher.max-pool-size"))
} finally {
- System.clearProperty("config.strategy")
-
- TestEnvFirstStrategy.removeEnvVar("CONFIG_42___a")
- TestEnvFirstStrategy.removeEnvVar("CONFIG_a_b_c")
- TestEnvFirstStrategy.removeEnvVar("CONFIG_a__c")
- TestEnvFirstStrategy.removeEnvVar("CONFIG_a___c")
-
- TestEnvFirstStrategy.removeEnvVar("CONFIG_akka_version")
- TestEnvFirstStrategy.removeEnvVar("CONFIG_akka_event__handler__dispatcher_max__pool__size")
+ System.clearProperty("config.override_with_env_vars")
}
}
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 5eed422ac..4c72643ea 100644
--- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
@@ -654,24 +654,22 @@ class PublicApiTest extends TestUtils {
}
@Test
- def supportsEnvFirstConfigLoadingStrategy(): Unit = {
- assertEquals("config.strategy is not set", null, System.getProperty("config.strategy"))
+ def loadEnvironmentVariablesOverridesIfConfigured(): Unit = {
+ assertEquals("config.override_with_env_vars is not set", null, System.getProperty("config.override_with_env_vars"))
- TestEnvFirstStrategy.putEnvVar("CONFIG_a", "5")
- System.setProperty("config.strategy", classOf[EnvFirstConfigLoadingStrategy].getCanonicalName)
+ System.setProperty("config.override_with_env_vars", "true")
try {
- val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
- Map("reference.conf" -> resourceFile("a_1.conf").toURI.toURL()))
+ val loaderB2 = new TestClassLoader(this.getClass().getClassLoader(),
+ Map("reference.conf" -> resourceFile("b_2.conf").toURI.toURL()))
- val configA1 = withContextClassLoader(loaderA1) {
+ val configB2 = withContextClassLoader(loaderB2) {
ConfigFactory.load()
}
- assertEquals(5, configA1.getInt("a"))
+ assertEquals(5, configB2.getInt("b"))
} finally {
- System.clearProperty("config.strategy")
- TestEnvFirstStrategy.removeEnvVar("CONFIG_a")
+ System.clearProperty("config.override_with_env_vars")
}
}
@@ -1168,10 +1166,3 @@ object TestStrategy {
def getIncovations() = invocations
def increment() = invocations += 1
}
-
-object TestEnvFirstStrategy extends EnvFirstConfigLoadingStrategy {
- def putEnvVar(key: String, value: String) =
- EnvFirstConfigLoadingStrategy.env.put(key, value)
- def removeEnvVar(key: String) =
- EnvFirstConfigLoadingStrategy.env.remove(key)
-}
From 81ae9d93ff2b5b6de836da3954450459427150bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois?=
Date: Fri, 8 Mar 2019 08:54:37 +0100
Subject: [PATCH 53/83] add new Rust port to README.md
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 28d51af89..916d757b0 100644
--- a/README.md
+++ b/README.md
@@ -893,6 +893,10 @@ format.
* https://github.com/akkadotnet/HOCON
+#### Rust port
+
+ * https://github.com/mockersf/hocon.rs
+
#### Linting tool
* A web based linting tool http://www.hoconlint.com/
From bf57edb7f220682caf186421ad2c7bb9934504d5 Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Fri, 8 Mar 2019 14:26:47 +0000
Subject: [PATCH 54/83] fixed review comments
---
.../src/main/java/com/typesafe/config/ConfigFactory.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/ConfigFactory.java b/config/src/main/java/com/typesafe/config/ConfigFactory.java
index 8405520f5..4937c8d3b 100644
--- a/config/src/main/java/com/typesafe/config/ConfigFactory.java
+++ b/config/src/main/java/com/typesafe/config/ConfigFactory.java
@@ -384,10 +384,10 @@ public static Config defaultReference(ClassLoader loader) {
* @return the default override configuration
*/
public static Config defaultOverrides() {
- if (!getOverrideWithEnv()) {
- return systemProperties();
- } else {
+ if (getOverrideWithEnv()) {
return systemEnvironmentOverrides().withFallback(systemProperties());
+ } else {
+ return systemProperties();
}
}
@@ -589,7 +589,7 @@ public static Config systemProperties() {
* This method can return a global immutable singleton, so it's preferred
* over parsing system properties yourself.
*
- * {@link #defaultOverrides} will include the system system environment variables as
+ * {@link #defaultOverrides} will include the system environment variables as
* overrides if `config.override_with_env_vars` is set to `true`.
*
* @return system environment variable overrides parsed into a Config
From 5d8ba54679ef091cf21b206e8872dd067dea697d Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Fri, 8 Mar 2019 14:53:14 +0000
Subject: [PATCH 55/83] Added a description of the new property in Readme
---
README.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/README.md b/README.md
index 28d51af89..d967fd6fc 100644
--- a/README.md
+++ b/README.md
@@ -675,6 +675,24 @@ value just disappear if the substitution is not found:
// this array could have one or two elements
path = [ "a", ${?OPTIONAL_A} ]
+By setting the JVM property `-Dconfig.override_with_env_vars=true`
+it is possible to override any configuration value using environment
+variables even if an explicit substitution is not specified.
+
+The environment variable value will override any pre-existing value
+and also any value provided as Java property.
+
+With this option enabled only environment variables starting with
+`CONFIG_FORCE_` are considered, and the name is mangled as follows:
+
+ - the prefix `CONFIG_FORCE_` is stripped
+ - single underscore(`_`) is converted into a dot(`.`)
+ - double underscore(`__`) is converted into a dash(`-`)
+ - triple underscore(`___`) is converted into a single underscore(`_`)
+
+i.e. The environment variable `CONFIG_FORCE_a_b__c___d` set the
+configuration key `a.b-c_d`
+
### Concatenation
Values _on the same line_ are concatenated (for strings and
From d38b91904f7bf300ce0e983a923cc9332cb76b93 Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Fri, 15 Mar 2019 16:40:59 +0000
Subject: [PATCH 56/83] Detail resons for _ sustitutions
---
README.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/README.md b/README.md
index d967fd6fc..23ef139e4 100644
--- a/README.md
+++ b/README.md
@@ -693,6 +693,15 @@ With this option enabled only environment variables starting with
i.e. The environment variable `CONFIG_FORCE_a_b__c___d` set the
configuration key `a.b-c_d`
+Rationale the name mangling:
+
+Most shells (e.g. bash, sh, etc.) doesn't support any character other
+than alphanumeric and `_` in environment variables names.
+In HOCON the default separator is `.` so it is directly translated to a
+single `_` for convenience; `-` and `_` are less often present in config
+keys but they have to be representable and the only possible mapping is
+`_` repeated.
+
### Concatenation
Values _on the same line_ are concatenated (for strings and
From a05923dd7f08828eb0937b5b1c68559065660435 Mon Sep 17 00:00:00 2001
From: Aaron Pritzlaff
Date: Tue, 19 Mar 2019 17:34:49 +0000
Subject: [PATCH 57/83] Added reference to args4c for command-line-to-config
utils
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 916d757b0..681a4f62d 100644
--- a/README.md
+++ b/README.md
@@ -856,6 +856,7 @@ format.
* Cedi Config https://github.com/ccadllc/cedi-config
* Cfg https://github.com/carueda/cfg
* circe-config https://github.com/circe/circe-config
+ * args4c https://github.com/aaronp/args4c
#### Clojure wrappers for the Java library
From f0816e556b903a3df5e50d0fb90a6f0c001dd132 Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Thu, 21 Mar 2019 08:52:42 +0000
Subject: [PATCH 58/83] Move rationale to code and implement invalidate cache
---
README.md | 9 ---------
.../java/com/typesafe/config/ConfigFactory.java | 1 +
.../java/com/typesafe/config/impl/ConfigImpl.java | 14 ++++++++++++++
3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/README.md b/README.md
index 23ef139e4..d967fd6fc 100644
--- a/README.md
+++ b/README.md
@@ -693,15 +693,6 @@ With this option enabled only environment variables starting with
i.e. The environment variable `CONFIG_FORCE_a_b__c___d` set the
configuration key `a.b-c_d`
-Rationale the name mangling:
-
-Most shells (e.g. bash, sh, etc.) doesn't support any character other
-than alphanumeric and `_` in environment variables names.
-In HOCON the default separator is `.` so it is directly translated to a
-single `_` for convenience; `-` and `_` are less often present in config
-keys but they have to be representable and the only possible mapping is
-`_` repeated.
-
### Concatenation
Values _on the same line_ are concatenated (for strings and
diff --git a/config/src/main/java/com/typesafe/config/ConfigFactory.java b/config/src/main/java/com/typesafe/config/ConfigFactory.java
index 4937c8d3b..4b91a1ea4 100644
--- a/config/src/main/java/com/typesafe/config/ConfigFactory.java
+++ b/config/src/main/java/com/typesafe/config/ConfigFactory.java
@@ -502,6 +502,7 @@ public static void invalidateCaches() {
// all caches
ConfigImpl.reloadSystemPropertiesConfig();
ConfigImpl.reloadEnvVariablesConfig();
+ ConfigImpl.reloadEnvVariablesOverridesConfig();
}
/**
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 f9057ede5..ffd2ba891 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
@@ -364,6 +364,14 @@ public static void reloadEnvVariablesConfig() {
private static AbstractConfigObject loadEnvVariablesOverrides() {
Map env = new HashMap(System.getenv());
Map result = new HashMap(System.getenv());
+ // Rationale on name mangling:
+ //
+ // Most shells (e.g. bash, sh, etc.) doesn't support any character other
+ // than alphanumeric and `_` in environment variables names.
+ // In HOCON the default separator is `.` so it is directly translated to a
+ // single `_` for convenience; `-` and `_` are less often present in config
+ // keys but they have to be representable and the only possible mapping is
+ // `_` repeated.
for (String key : env.keySet()) {
if (key.startsWith(ENV_VAR_OVERRIDE_PREFIX)) {
StringBuilder builder = new StringBuilder();
@@ -412,6 +420,12 @@ public static Config envVariablesOverridesAsConfig() {
return envVariablesOverridesAsConfigObject().toConfig();
}
+ public static void reloadEnvVariablesOverridesConfig() {
+ // ConfigFactory.invalidateCaches() relies on this having the side
+ // effect that it drops all caches
+ EnvVariablesOverridesHolder.envVariables = loadEnvVariablesOverrides();
+ }
+
public static Config defaultReference(final ClassLoader loader) {
return computeCachedConfig(loader, "defaultReference", new Callable() {
@Override
From f686abd341fe2902d8fc629ebea15fdb5808804a Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Thu, 21 Mar 2019 09:02:48 +0000
Subject: [PATCH 59/83] Bump sbt version
---
project/build.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project/build.properties b/project/build.properties
index 72f902892..c0bab0494 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.2.7
+sbt.version=1.2.8
From fd7d9cc89ea7c76a50c0edff65686906389e798d Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Thu, 21 Mar 2019 10:01:27 +0000
Subject: [PATCH 60/83] Remove Puppy Crawl references
---
config/checkstyle-config.xml | 5 ++---
config/checkstyle-suppressions.xml | 3 ++-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/config/checkstyle-config.xml b/config/checkstyle-config.xml
index 0fc2c197a..064ac59a5 100644
--- a/config/checkstyle-config.xml
+++ b/config/checkstyle-config.xml
@@ -1,8 +1,7 @@
-
-
diff --git a/config/checkstyle-suppressions.xml b/config/checkstyle-suppressions.xml
index 62d514067..ca3fb2d15 100644
--- a/config/checkstyle-suppressions.xml
+++ b/config/checkstyle-suppressions.xml
@@ -1,5 +1,6 @@
-
From 0e3b472aadd26a9c42bb73f21e2ddd09dcea98ce Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Thu, 21 Mar 2019 10:50:48 +0000
Subject: [PATCH 61/83] Move env mangling to ConfigImplUtil
---
.../com/typesafe/config/impl/ConfigImpl.java | 36 ++-------------
.../typesafe/config/impl/ConfigImplUtil.java | 46 +++++++++++++++++++
.../com/typesafe/config/impl/ConfigTest.scala | 16 +++++++
3 files changed, 66 insertions(+), 32 deletions(-)
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 ffd2ba891..e96913287 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
@@ -361,43 +361,15 @@ public static void reloadEnvVariablesConfig() {
EnvVariablesHolder.envVariables = loadEnvVariables();
}
+
+
private static AbstractConfigObject loadEnvVariablesOverrides() {
Map env = new HashMap(System.getenv());
Map result = new HashMap(System.getenv());
- // Rationale on name mangling:
- //
- // Most shells (e.g. bash, sh, etc.) doesn't support any character other
- // than alphanumeric and `_` in environment variables names.
- // In HOCON the default separator is `.` so it is directly translated to a
- // single `_` for convenience; `-` and `_` are less often present in config
- // keys but they have to be representable and the only possible mapping is
- // `_` repeated.
+
for (String key : env.keySet()) {
if (key.startsWith(ENV_VAR_OVERRIDE_PREFIX)) {
- StringBuilder builder = new StringBuilder();
-
- String strippedPrefix = key.substring(ENV_VAR_OVERRIDE_PREFIX.length(), key.length());
-
- int underscores = 0;
- for (char c : strippedPrefix.toCharArray()) {
- if (c == '_') {
- underscores++;
- } else {
- switch (underscores) {
- case 1: builder.append('.');
- break;
- case 2: builder.append('-');
- break;
- case 3: builder.append('_');
- break;
- }
- underscores = 0;
- builder.append(c);
- }
- }
-
- String propertyKey = builder.toString();
- result.put(propertyKey, env.get(key));
+ result.put(ConfigImplUtil.envVariableAsProperty(key, ENV_VAR_OVERRIDE_PREFIX), env.get(key));
}
}
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java b/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
index 1dcc43d3d..1a8ffc1db 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImplUtil.java
@@ -235,6 +235,52 @@ static String toCamelCase(String originalName) {
return nameBuilder.toString();
}
+ private static char underscoreMappings(int num) {
+ // Rationale on name mangling:
+ //
+ // Most shells (e.g. bash, sh, etc.) doesn't support any character other
+ // than alphanumeric and `_` in environment variables names.
+ // In HOCON the default separator is `.` so it is directly translated to a
+ // single `_` for convenience; `-` and `_` are less often present in config
+ // keys but they have to be representable and the only possible mapping is
+ // `_` repeated.
+ switch (num) {
+ case 1: return '.';
+ case 2: return '-';
+ case 3: return '_';
+ default: return 0;
+ }
+ }
+
+ static String envVariableAsProperty(String variable, String prefix) throws ConfigException {
+ StringBuilder builder = new StringBuilder();
+
+ String strippedPrefix = variable.substring(prefix.length(), variable.length());
+
+ int underscores = 0;
+ for (char c : strippedPrefix.toCharArray()) {
+ if (c == '_') {
+ underscores++;
+ } else {
+ if (underscores > 0 && underscores < 4) {
+ builder.append(underscoreMappings(underscores));
+ } else if (underscores > 3) {
+ throw new ConfigException.BadPath(variable, "Environment variable contains an un-mapped number of underscores.");
+ }
+ underscores = 0;
+ builder.append(c);
+ }
+ }
+
+ if (underscores > 0 && underscores < 4) {
+ builder.append(underscoreMappings(underscores));
+ } else if (underscores > 3) {
+ throw new ConfigException.BadPath(variable, "Environment variable contains an un-mapped number of underscores.");
+ }
+
+ return builder.toString();
+ }
+
/**
* Guess configuration syntax from given filename.
*
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 853aa249f..eeda74e70 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -1090,6 +1090,22 @@ class ConfigTest extends TestUtils {
assertEquals(10, resolved.getInt("bar.nested.a.q"))
}
+ @Test
+ def testEnvVariablesNameMangling() {
+ assertEquals("a", ConfigImplUtil.envVariableAsProperty("prefix_a", "prefix_"))
+ assertEquals("a.b", ConfigImplUtil.envVariableAsProperty("prefix_a_b", "prefix_"))
+ assertEquals("a.b.c", ConfigImplUtil.envVariableAsProperty("prefix_a_b_c", "prefix_"))
+ assertEquals("a.b-c-d", ConfigImplUtil.envVariableAsProperty("prefix_a_b__c__d", "prefix_"))
+ assertEquals("a.b_c_d", ConfigImplUtil.envVariableAsProperty("prefix_a_b___c___d", "prefix_"))
+
+ intercept[ConfigException.BadPath] {
+ ConfigImplUtil.envVariableAsProperty("prefix_____", "prefix_")
+ }
+ intercept[ConfigException.BadPath] {
+ ConfigImplUtil.envVariableAsProperty("prefix_a_b___c____d", "prefix_")
+ }
+ }
+
@Test
def testLoadWithEnvSubstitutions() {
System.setProperty("config.override_with_env_vars", "true")
From 2efd1fa06ad210f82f688d67a6ec1b3afec8e5a7 Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Thu, 21 Mar 2019 10:53:10 +0000
Subject: [PATCH 62/83] minor fix
---
config/checkstyle-config.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/checkstyle-config.xml b/config/checkstyle-config.xml
index 064ac59a5..ae2259fa7 100644
--- a/config/checkstyle-config.xml
+++ b/config/checkstyle-config.xml
@@ -1,6 +1,6 @@
From 4836b452ef3fa80d803df9230573550137ac3b5c Mon Sep 17 00:00:00 2001
From: Andrea Peruffo
Date: Thu, 21 Mar 2019 10:54:31 +0000
Subject: [PATCH 63/83] fix again XML
---
config/checkstyle-config.xml | 2 +-
config/checkstyle-suppressions.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/checkstyle-config.xml b/config/checkstyle-config.xml
index ae2259fa7..148167f31 100644
--- a/config/checkstyle-config.xml
+++ b/config/checkstyle-config.xml
@@ -1,5 +1,5 @@
-
diff --git a/config/checkstyle-suppressions.xml b/config/checkstyle-suppressions.xml
index ca3fb2d15..300751899 100644
--- a/config/checkstyle-suppressions.xml
+++ b/config/checkstyle-suppressions.xml
@@ -1,5 +1,5 @@
-
From 93cb38a60d9c933aa43de656dcfdc2cfb84fb115 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martynas=20Mickevi=C4=8Dius?=
Date: Thu, 18 Apr 2019 12:29:27 +0000
Subject: [PATCH 64/83] Add release notes for 1.3.4 (#628)
* Add release notes for 1.3.4
---
NEWS.md | 12 ++++++++++++
README.md | 4 ++--
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/NEWS.md b/NEWS.md
index 12fd05e14..a4e5b84f4 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,15 @@
+# 1.3.4: April 18, 2018
+
+- it is now possible to override any configuration setting from environment variables ([#620](/../../pull/620)) thanks to [@andreaTP](https://github.com/andreaTP)
+- added support for integer keys that are longer than `Int` ([#568](/../../pull/568)) thanks to [@michalmela](https://github.com/michalmela)
+- `Missing` exception now has a reference to the origin `Config` ([#585](/../../pull/585)) thanks to [@vagola](https://github.com/vagola)
+- performance improvements to `resolve()` ([#578](/../../pull/578)) thanks to [@sam-token](https://github.com/sam-token)
+- config file syntax is now resolved when parsing `InputStream` ([#573](/../../pull/573)) thanks to [@ntviet18](https://github.com/ntviet18)
+- it is now possible to use `@Optional` on keys that are reserved words ([#570](/../../pull/570)) thanks to [@radist-nt](https://github.com/radist-nt)
+- `ValidationProblem` is now serializable ([#437](/../../pull/437)) thanks to [@iantabolt](https://github.com/iantabolt)
+
+All of the merged PRs can be found in the [release milestone](https://github.com/lightbend/config/milestone/4?closed=1).
+
# 1.3.3: February 22, 2018
- artifact now includes `Automatic-Module-Name` which makes it consumable as Java 9 module.
diff --git a/README.md b/README.md
index 7389e5e99..5e6a3529d 100644
--- a/README.md
+++ b/README.md
@@ -106,12 +106,12 @@ You can find published releases on Maven Central.
com.typesafeconfig
- 1.3.2
+ 1.3.4
sbt dependency:
- libraryDependencies += "com.typesafe" % "config" % "1.3.2"
+ libraryDependencies += "com.typesafe" % "config" % "1.3.4"
Link for direct download if you don't use a dependency manager:
From 152366baf609c02c680e11b28d307d37709d260a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martynas=20Mickevi=C4=8Dius?=
Date: Thu, 18 Apr 2019 15:57:40 +0300
Subject: [PATCH 65/83] Update to the latest sbt-pgp
---
project/plugins.sbt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/project/plugins.sbt b/project/plugins.sbt
index dd15b5dd1..38196f0ac 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,6 +1,6 @@
addSbtPlugin("com.github.sbt" % "sbt-findbugs" % "2.0.0")
addSbtPlugin("com.github.sbt" % "sbt-jacoco" % "3.1.0")
-addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.1")
+addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.0-M2")
addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.9.3")
addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2")
From 0f36308a0b7bf88bcfee9dc33355ab91859d2137 Mon Sep 17 00:00:00 2001
From: Mario Cornejo
Date: Fri, 26 Apr 2019 16:53:53 +0200
Subject: [PATCH 66/83] Update NEWS.md
Typo in the year
---
NEWS.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/NEWS.md b/NEWS.md
index a4e5b84f4..3dffc59e9 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,4 +1,4 @@
-# 1.3.4: April 18, 2018
+# 1.3.4: April 18, 2019
- it is now possible to override any configuration setting from environment variables ([#620](/../../pull/620)) thanks to [@andreaTP](https://github.com/andreaTP)
- added support for integer keys that are longer than `Int` ([#568](/../../pull/568)) thanks to [@michalmela](https://github.com/michalmela)
From a9981371e2d191e6e6d8986e3ebe50ef652c6d6b Mon Sep 17 00:00:00 2001
From: Arnout Engelen
Date: Tue, 7 May 2019 15:21:54 +0200
Subject: [PATCH 67/83] Test on JDK 11
---
.travis.yml | 9 ++++++++-
build.sbt | 3 ++-
.../main/java/com/typesafe/config/impl/ConfigImpl.java | 8 +++++++-
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index df74bfb98..8e7e88b54 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,11 +7,18 @@ before_install:
# using jabba for custom jdk management
- curl -sL https://raw.githubusercontent.com/shyiko/jabba/0.11.2/install.sh | bash && . ~/.jabba/jabba.sh
- jabba install adopt@1.8.202-08
- - java -version
+ - jabba install adopt@1.11.0-1
script:
+ - jabba use $JDK
+ - java -version
- sbt ++$TRAVIS_SCALA_VERSION test doc
+jobs:
+ include:
+ - env: JDK=adopt@1.8.202-08
+ - env: JDK=adopt@1.11.0-1
+
before_cache:
# Remove to avoid unnecessary cache updates
- find $HOME/.sbt -name "*.lock" -delete
diff --git a/build.sbt b/build.sbt
index 15260557a..8a6b87f78 100644
--- a/build.sbt
+++ b/build.sbt
@@ -151,7 +151,8 @@ lazy val commonSettings: Seq[Setting[_]] = Def.settings(
unpublished,
scalariformPreferences := scalariformPreferences.value
.setPreference(IndentSpaces, 4)
- .setPreference(FirstArgumentOnNewline, Preserve)
+ .setPreference(FirstArgumentOnNewline, Preserve),
+ Compile / compile / javacOptions ++= Seq("-source", "1.8", "-target", "1.8"),
)
def proj(id: String, base: File) = Project(id, base) settings commonSettings
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 e96913287..c807046db 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
@@ -302,7 +302,13 @@ private static Properties getSystemProperties() {
final Properties systemProperties = System.getProperties();
final Properties systemPropertiesCopy = new Properties();
synchronized (systemProperties) {
- systemPropertiesCopy.putAll(systemProperties);
+ for (Map.Entry entry: systemProperties.entrySet()) {
+ // Java 11 introduces 'java.version.date', but we don't want that to
+ // overwrite 'java.version'
+ if (!entry.getKey().toString().startsWith("java.version.")) {
+ systemPropertiesCopy.put(entry.getKey(), entry.getValue());
+ }
+ }
}
return systemPropertiesCopy;
}
From 0dd6c2237f74c8561834b701947394c53234e1b4 Mon Sep 17 00:00:00 2001
From: Marcos Pereira
Date: Tue, 7 May 2019 16:19:25 +0200
Subject: [PATCH 68/83] newer jdk11
Co-Authored-By: raboof
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 8e7e88b54..eb52df64c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ before_install:
# using jabba for custom jdk management
- curl -sL https://raw.githubusercontent.com/shyiko/jabba/0.11.2/install.sh | bash && . ~/.jabba/jabba.sh
- jabba install adopt@1.8.202-08
- - jabba install adopt@1.11.0-1
+ - jabba install adopt@1.11.0-3
script:
- jabba use $JDK
From 4f8d507ecae827d87c043f3abd45b0e5c9c50c8d Mon Sep 17 00:00:00 2001
From: Marcos Pereira
Date: Tue, 7 May 2019 16:19:36 +0200
Subject: [PATCH 69/83] Newer jdk8
Co-Authored-By: raboof
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index eb52df64c..471c939bb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,7 +16,7 @@ script:
jobs:
include:
- - env: JDK=adopt@1.8.202-08
+ - env: JDK=adopt@1.8.212-03
- env: JDK=adopt@1.11.0-1
before_cache:
From 12abec262970489894a076b093a422267f644a53 Mon Sep 17 00:00:00 2001
From: Marcos Pereira
Date: Tue, 7 May 2019 16:19:51 +0200
Subject: [PATCH 70/83] Use latest jabba
Co-Authored-By: raboof
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 471c939bb..55cb53de3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ language: scala
before_install:
# using jabba for custom jdk management
- - curl -sL https://raw.githubusercontent.com/shyiko/jabba/0.11.2/install.sh | bash && . ~/.jabba/jabba.sh
+ - curl -sL https://git.io/jabba | bash && . ~/.jabba/jabba.sh
- jabba install adopt@1.8.202-08
- jabba install adopt@1.11.0-3
From 215ad7eae5007157bbf3975793b6f7a0fc3ec5ca Mon Sep 17 00:00:00 2001
From: Marcos Pereira
Date: Tue, 7 May 2019 16:20:09 +0200
Subject: [PATCH 71/83] Use latest jdk8
Co-Authored-By: raboof
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 55cb53de3..a2033bba9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,7 @@ language: scala
before_install:
# using jabba for custom jdk management
- curl -sL https://git.io/jabba | bash && . ~/.jabba/jabba.sh
- - jabba install adopt@1.8.202-08
+ - jabba install adopt@1.8.212-03
- jabba install adopt@1.11.0-3
script:
From 691da05f22c50c03c10e409410b222979a806ac7 Mon Sep 17 00:00:00 2001
From: Marcos Pereira
Date: Tue, 7 May 2019 16:20:31 +0200
Subject: [PATCH 72/83] Use latest jdk11
Co-Authored-By: raboof
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index a2033bba9..09fa68d4b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@ script:
jobs:
include:
- env: JDK=adopt@1.8.212-03
- - env: JDK=adopt@1.11.0-1
+ - env: JDK=adopt@1.11.0-3
before_cache:
# Remove to avoid unnecessary cache updates
From cec08b7168df5b5266b5f66f6dab59f3ec321d9a Mon Sep 17 00:00:00 2001
From: Marcos Pereira
Date: Tue, 7 May 2019 10:24:03 -0400
Subject: [PATCH 73/83] Fix formatting detail
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 09fa68d4b..66f6e229a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,8 +5,8 @@ language: scala
before_install:
# using jabba for custom jdk management
- - curl -sL https://git.io/jabba | bash && . ~/.jabba/jabba.sh
- - jabba install adopt@1.8.212-03
+ - curl -sL https://git.io/jabba | bash && . ~/.jabba/jabba.sh
+ - jabba install adopt@1.8.212-03
- jabba install adopt@1.11.0-3
script:
From 4c83d9a860bc22180a4c58f4bdfb71bc86fc643f Mon Sep 17 00:00:00 2001
From: Eric Richardson
Date: Wed, 22 May 2019 11:13:09 -0700
Subject: [PATCH 74/83] Update README to include sconfig supported platforms
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5e6a3529d..b05f03d5d 100644
--- a/README.md
+++ b/README.md
@@ -886,7 +886,7 @@ format.
#### Scala port
* SHocon https://github.com/akka-js/shocon (Supports Scala.js and Scala Native)
- * sconfig https://github.com/ekrich/sconfig
+ * sconfig https://github.com/ekrich/sconfig (Supports JVM, Scala Native, and Scala.js)
#### Ruby port
From 364b9ad1ceceddeb9223fb8063cf2003f99f4658 Mon Sep 17 00:00:00 2001
From: Havoc Pennington
Date: Thu, 23 May 2019 06:14:00 -0400
Subject: [PATCH 75/83] Fix spelling typo in readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5e6a3529d..cd2d2e84b 100644
--- a/README.md
+++ b/README.md
@@ -924,7 +924,7 @@ format.
* https://hocon-playground.herokuapp.com/
-# Maintanance notes
+# Maintenance notes
## License
From 97f3032b3e9b46ebf4731b791be52381d08e12d8 Mon Sep 17 00:00:00 2001
From: Havoc Pennington
Date: Thu, 23 May 2019 07:11:22 -0400
Subject: [PATCH 76/83] =?UTF-8?q?Note=20in=20README=20that=20substitutions?=
=?UTF-8?q?=20don=E2=80=99t=20work=20inside=20quotes=20(#634)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Note in README that substitutions don’t work inside quotes
There’s more on this in HOCON.md but can’t hurt to repeat, people do miss it.
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5e2f05b0d..79f8de1b6 100644
--- a/README.md
+++ b/README.md
@@ -706,9 +706,12 @@ string `foo` are concatenated into a string `42 foo`:
When concatenating values into a string, leading and trailing
whitespace is stripped but whitespace between values is kept.
-Unquoted strings also support substitutions of course:
+Quoted or unquoted strings can also concatenate with substitutions of course:
tasks-url : ${base-url}/tasks
+ tasks-url : ${base-url}"tasks:colon-must-be-quoted"
+
+Note: the `${}` syntax must be outside the quotes!
A concatenation can refer to earlier values of the same field:
From 14c882dab8fafa41d0c1fd9927ef44795660c4ac Mon Sep 17 00:00:00 2001
From: James Roper
Date: Tue, 20 Aug 2019 23:02:50 +1000
Subject: [PATCH 77/83] Allow application.conf to override variables in
reference.conf (#619)
* Allow application.conf to override variables in reference.conf
Fixes #167
This only affects the output of `ConfigFactory.load`. It does not change
`ConfigFactory.defaultReference`. This uses the unresolved
`reference.conf` in the building of configuration in
`ConfigFactory.load`, effectively allowing `application.conf` properties
to override variable substitutions in `reference.conf`.
However, it still requires `reference.conf` to be fully resolvable, if
it isn't, an exception will be thrown. So two resolves are still done
during load, it's just that the output of the resolve of
`reference.conf` isn't used in building the final configuration. The
documentation has been updated to reflect this behavior.
The reasoning behind this change can be read about in #167, but
essentially, it is not uncommon for configuration properties to depend
on each other by default, a good example of this is directory
hierarchies, where you might have a configuration option for a base
directory, and then a configuration for the log directory that by
default is under the base directory, and within that a configuration for
individual log files which by default are under the log directory.
Without allowing variable substitutions in `reference.conf` from
`application.conf`, there is no point in defining a configuration option
for the base directory since changing it won't have any impact, and each
path defined that depends on it will have to be manually overridden.
This limitation is contrary to convention over configuration best
practices, and hence not desirable in a configuration library.
* Renamed public method to defaultReferenceUnresolved
Also added the methods to ConfigFactory, as requested in code review.
---
README.md | 28 ++--------
.../com/typesafe/config/ConfigException.java | 12 +++++
.../com/typesafe/config/ConfigFactory.java | 53 ++++++++++++++++++-
.../com/typesafe/config/impl/ConfigImpl.java | 34 ++++++++++--
...13-application-override-substitutions.conf | 1 +
.../test13-reference-bad-substitutions.conf | 1 +
.../test13-reference-with-substitutions.conf | 2 +
.../typesafe/config/impl/PublicApiTest.scala | 22 ++++++++
8 files changed, 125 insertions(+), 28 deletions(-)
create mode 100644 config/src/test/resources/test13-application-override-substitutions.conf
create mode 100644 config/src/test/resources/test13-reference-bad-substitutions.conf
create mode 100644 config/src/test/resources/test13-reference-with-substitutions.conf
diff --git a/README.md b/README.md
index 79f8de1b6..5f24a47c1 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,6 @@ to merge it in.
- [Inheritance](#inheritance)
- [Optional system or env variable overrides](#optional-system-or-env-variable-overrides)
- [Concatenation](#concatenation)
- - [`reference.conf` can't refer to `application.conf`](#referenceconf-cant-refer-to-applicationconf)
- [Miscellaneous Notes](#miscellaneous-notes)
- [Debugging Your Configuration](#debugging-your-configuration)
- [Supports Java 8 and Later](#supports-java-8-and-later)
@@ -277,23 +276,14 @@ system properties.
The substitution syntax `${foo.bar}` will be resolved
twice. First, all the `reference.conf` files are merged and then
the result gets resolved. Second, all the `application.conf` are
-layered over the `reference.conf` and the result of that gets
-resolved again.
+layered over the unresolved `reference.conf` and the result of that
+gets resolved again.
The implication of this is that the `reference.conf` stack has to
be self-contained; you can't leave an undefined value `${foo.bar}`
-to be provided by `application.conf`, or refer to `${foo.bar}` in
-a way that you want to allow `application.conf` to
-override. However, `application.conf` can refer to a `${foo.bar}`
-in `reference.conf`.
-
-This can be frustrating at times, but possible workarounds
-include:
-
- * putting an `application.conf` in a library jar, alongside the
-`reference.conf`, with values intended for later resolution.
- * putting some logic in code instead of building up values in the
- config itself.
+to be provided by `application.conf`. It is however possible to
+override a variable that `reference.conf` refers to, as long as
+`reference.conf` also defines that variable itself.
### Merging config trees
@@ -758,14 +748,6 @@ concatenation, but not object/array concatenation. `+=` does not
work in Play/Akka 2.0 either. Post-2.0 versions support these
features.
-### `reference.conf` can't refer to `application.conf`
-
-Please see this
-earlier section; all `reference.conf` have substitutions
-resolved first, without `application.conf` in the stack, so the
-reference stack has to be self-contained.
-
## Miscellaneous Notes
### Debugging Your Configuration
diff --git a/config/src/main/java/com/typesafe/config/ConfigException.java b/config/src/main/java/com/typesafe/config/ConfigException.java
index f35e8dbea..2e6d99ab7 100644
--- a/config/src/main/java/com/typesafe/config/ConfigException.java
+++ b/config/src/main/java/com/typesafe/config/ConfigException.java
@@ -284,13 +284,25 @@ public Parse(ConfigOrigin origin, String message) {
public static class UnresolvedSubstitution extends Parse {
private static final long serialVersionUID = 1L;
+ private final String detail;
+
public UnresolvedSubstitution(ConfigOrigin origin, String detail, Throwable cause) {
super(origin, "Could not resolve substitution to a value: " + detail, cause);
+ this.detail = detail;
}
public UnresolvedSubstitution(ConfigOrigin origin, String detail) {
this(origin, detail, null);
}
+
+ private UnresolvedSubstitution(UnresolvedSubstitution wrapped, ConfigOrigin origin, String message) {
+ super(origin, message, wrapped);
+ this.detail = wrapped.detail;
+ }
+
+ public UnresolvedSubstitution addExtraDetail(String extra) {
+ return new UnresolvedSubstitution(this, origin(), String.format(extra, detail));
+ }
}
/**
diff --git a/config/src/main/java/com/typesafe/config/ConfigFactory.java b/config/src/main/java/com/typesafe/config/ConfigFactory.java
index 4b91a1ea4..12f9aaec0 100644
--- a/config/src/main/java/com/typesafe/config/ConfigFactory.java
+++ b/config/src/main/java/com/typesafe/config/ConfigFactory.java
@@ -211,7 +211,8 @@ public static Config load(Config config, ConfigResolveOptions resolveOptions) {
* @return resolved configuration with overrides and fallbacks added
*/
public static Config load(ClassLoader loader, Config config, ConfigResolveOptions resolveOptions) {
- return defaultOverrides(loader).withFallback(config).withFallback(defaultReference(loader))
+ return defaultOverrides(loader).withFallback(config)
+ .withFallback(ConfigImpl.defaultReferenceUnresolved(loader))
.resolve(resolveOptions);
}
@@ -368,6 +369,56 @@ public static Config defaultReference(ClassLoader loader) {
return ConfigImpl.defaultReference(loader);
}
+ /**
+ * Obtains the default reference configuration, which is currently created
+ * by merging all resources "reference.conf" found on the classpath and
+ * overriding the result with system properties.
+ *
+ *
+ * While the returned reference configuration is guaranteed to be
+ * resolvable (that is, there will be no substitutions that cannot be
+ * resolved), it is returned in an unresolved state for the purpose of
+ * allowing substitutions to be overridden by a config layer that falls
+ * back to this one.
+ *
+ *
+ * Libraries and frameworks should ship with a "reference.conf" in their
+ * jar.
+ *
+ *
+ * The reference config must be looked up in the class loader that contains
+ * the libraries that you want to use with this config, so the
+ * "reference.conf" for each library can be found. Use
+ * {@link #defaultReference(ClassLoader)} if the context class loader is not
+ * suitable.
+ *
+ *
+ * The {@link #load()} methods merge this configuration for you
+ * automatically.
+ *
+ *
+ * Future versions may look for reference configuration in more places. It
+ * is not guaranteed that this method only looks at
+ * "reference.conf".
+ *
+ * @return the unresolved default reference config for the context class
+ * loader
+ */
+ public static Config defaultReferenceUnresolved() {
+ return defaultReferenceUnresolved(checkedContextClassLoader("defaultReferenceUnresolved"));
+ }
+
+ /**
+ * Like {@link #defaultReferenceUnresolved()} but allows you to specify a
+ * class loader to use rather than the current context class loader.
+ *
+ * @param loader class loader to look for resources in
+ * @return the unresolved default reference config for this class loader
+ */
+ public static Config defaultReferenceUnresolved(ClassLoader loader) {
+ return ConfigImpl.defaultReferenceUnresolved(loader);
+ }
+
/**
* Obtains the default override configuration, which currently consists of
* system properties. The returned override configuration will already have
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 c807046db..f14c12af6 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigImpl.java
@@ -408,15 +408,41 @@ public static Config defaultReference(final ClassLoader loader) {
return computeCachedConfig(loader, "defaultReference", new Callable() {
@Override
public Config call() {
- Config unresolvedResources = Parseable
- .newResources("reference.conf",
- ConfigParseOptions.defaults().setClassLoader(loader))
- .parse().toConfig();
+ Config unresolvedResources = unresolvedReference(loader);
return systemPropertiesAsConfig().withFallback(unresolvedResources).resolve();
}
});
}
+ private static Config unresolvedReference(final ClassLoader loader) {
+ return computeCachedConfig(loader, "unresolvedReference", new Callable() {
+ @Override
+ public Config call() {
+ return Parseable.newResources("reference.conf",
+ ConfigParseOptions.defaults().setClassLoader(loader))
+ .parse().toConfig();
+ }
+ });
+ }
+
+ /**
+ * This returns the unresolved reference configuration, but before doing so,
+ * it verifies that the reference configuration resolves, to ensure that it
+ * is self contained and doesn't depend on any higher level configuration
+ * files.
+ */
+ public static Config defaultReferenceUnresolved(final ClassLoader loader) {
+ // First, verify that `reference.conf` resolves by itself.
+ try {
+ defaultReference(loader);
+ } catch (ConfigException.UnresolvedSubstitution e) {
+ throw e.addExtraDetail("Could not resolve substitution in reference.conf to a value: %s. All reference.conf files are required to be fully, independently resolvable, and should not require the presence of values for substitutions from further up the hierarchy.");
+ }
+ // Now load the unresolved version
+ return unresolvedReference(loader);
+ }
+
+
private static class DebugHolder {
private static String LOADS = "loads";
private static String SUBSTITUTIONS = "substitutions";
diff --git a/config/src/test/resources/test13-application-override-substitutions.conf b/config/src/test/resources/test13-application-override-substitutions.conf
new file mode 100644
index 000000000..506b2cada
--- /dev/null
+++ b/config/src/test/resources/test13-application-override-substitutions.conf
@@ -0,0 +1 @@
+b = "overridden"
\ No newline at end of file
diff --git a/config/src/test/resources/test13-reference-bad-substitutions.conf b/config/src/test/resources/test13-reference-bad-substitutions.conf
new file mode 100644
index 000000000..1b2615077
--- /dev/null
+++ b/config/src/test/resources/test13-reference-bad-substitutions.conf
@@ -0,0 +1 @@
+a = ${b}
\ No newline at end of file
diff --git a/config/src/test/resources/test13-reference-with-substitutions.conf b/config/src/test/resources/test13-reference-with-substitutions.conf
new file mode 100644
index 000000000..fcf7f995c
--- /dev/null
+++ b/config/src/test/resources/test13-reference-with-substitutions.conf
@@ -0,0 +1,2 @@
+a = ${b}
+b = "b"
\ No newline at end of file
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 4c72643ea..1643a4a31 100644
--- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala
@@ -1152,6 +1152,28 @@ include "onclasspath"
// missing underneath missing
intercept[ConfigException.Missing] { conf.getIsNull("x.c.y") }
}
+
+ @Test
+ def applicationConfCanOverrideReferenceConf(): Unit = {
+ val loader = new TestClassLoader(this.getClass.getClassLoader,
+ Map(
+ "reference.conf" -> resourceFile("test13-reference-with-substitutions.conf").toURI.toURL,
+ "application.conf" -> resourceFile("test13-application-override-substitutions.conf").toURI.toURL))
+
+ assertEquals("b", ConfigFactory.defaultReference(loader).getString("a"))
+ assertEquals("overridden", ConfigFactory.load(loader).getString("a"))
+ }
+
+ @Test(expected = classOf[ConfigException.UnresolvedSubstitution])
+ def referenceConfMustResolveIndependently(): Unit = {
+ val loader = new TestClassLoader(this.getClass.getClassLoader,
+ Map(
+ "reference.conf" -> resourceFile("test13-reference-bad-substitutions.conf").toURI.toURL,
+ "application.conf" -> resourceFile("test13-application-override-substitutions.conf").toURI.toURL))
+
+ ConfigFactory.load(loader)
+ }
+
}
class TestStrategy extends DefaultConfigLoadingStrategy {
From 558438aa2b0c05466e149a92ebef3133ce957edd Mon Sep 17 00:00:00 2001
From: Dmitry Ilyin
Date: Tue, 3 Sep 2019 21:35:07 +0300
Subject: [PATCH 78/83] Performance fix: added capacity parameter in ArrayLists
contructor when adding elements
---
config/src/main/java/com/typesafe/config/impl/ConfigParser.java | 2 +-
.../main/java/com/typesafe/config/impl/SimpleConfigOrigin.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigParser.java b/config/src/main/java/com/typesafe/config/impl/ConfigParser.java
index cce541636..1e562ace2 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigParser.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigParser.java
@@ -59,7 +59,7 @@ private AbstractConfigValue parseConcatenation(ConfigNodeConcatenation n) {
if (flavor == ConfigSyntax.JSON)
throw new ConfigException.BugOrBroken("Found a concatenation node in JSON");
- List values = new ArrayList();
+ List values = new ArrayList(n.children().size());
for (AbstractConfigNode node : n.children()) {
AbstractConfigValue v = null;
diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java b/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java
index a3dc3e4d5..9e05f9e91 100644
--- a/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java
+++ b/config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java
@@ -364,7 +364,7 @@ static ConfigOrigin mergeOrigins(Collection extends ConfigOrigin> stack) {
Iterator extends ConfigOrigin> i = stack.iterator();
return mergeTwo((SimpleConfigOrigin) i.next(), (SimpleConfigOrigin) i.next());
} else {
- List remaining = new ArrayList();
+ List remaining = new ArrayList(stack.size());
for (ConfigOrigin o : stack) {
remaining.add((SimpleConfigOrigin) o);
}
From 6c8d0d42271c01ca47dba76a7c841926077a811a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johan=20Andr=C3=A9n?=
Date: Mon, 14 Oct 2019 10:53:41 +0200
Subject: [PATCH 79/83] Release 1.4.0 (#655)
---
.travis.yml | 25 +++++++++++++------------
CONTRIBUTING.md | 36 +-----------------------------------
NEWS.md | 7 +++++++
README.md | 4 ++--
RELEASING.md | 37 +++++++++++++++++++++++++++++++++++++
build.sbt | 2 +-
6 files changed, 61 insertions(+), 50 deletions(-)
create mode 100644 RELEASING.md
diff --git a/.travis.yml b/.travis.yml
index 66f6e229a..980ed49e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,21 +3,22 @@ sudo: false
language: scala
-before_install:
- # using jabba for custom jdk management
- - curl -sL https://git.io/jabba | bash && . ~/.jabba/jabba.sh
- - jabba install adopt@1.8.212-03
- - jabba install adopt@1.11.0-3
-
-script:
- - jabba use $JDK
- - java -version
- - sbt ++$TRAVIS_SCALA_VERSION test doc
+before_install: curl -Ls https://git.io/jabba | bash && . ~/.jabba/jabba.sh
+install: jabba install "adopt@~1.$TRAVIS_JDK.0-0" && jabba use "$_" && java -Xmx32m -version
jobs:
include:
- - env: JDK=adopt@1.8.212-03
- - env: JDK=adopt@1.11.0-3
+ - stage: jdk8
+ name: "test and docs on jdk8"
+ script: sbt ++$TRAVIS_SCALA_VERSION test doc
+ - stage: jdk11
+ name: "test and docs on jdk11"
+ script: sbt ++$TRAVIS_SCALA_VERSION test doc
+ env: TRAVIS_JDK=11
+
+env:
+ global:
+ - TRAVIS_JDK=8
before_cache:
# Remove to avoid unnecessary cache updates
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 30ebc7fd8..255892ab2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -23,38 +23,4 @@ more revision will likely be needed.
# Making a release
-To make a release you'll need to be a maintainer with GitHub
-permissions to push to the master and gh-pages branches, and
-Sonatype permissions to publish.
-
-Here are the steps, which should be automated but aren't (PR
-welcome!):
-
- 1. write release notes in NEWS.md following the format
- already in there. update README with the new version.
- Commit.
- 2. create a signed git tag "vX.Y.Z"
- 3. start sbt; `show version` should confirm that the version was
- taken from the tag
- 4. clean
- 5. test (double check that release works)
- 6. doc (double check that docs build, plus build docs
- to be copied to gh-pages later)
- 7. if test or doc fails, delete the tag, fix it, start over.
- 8. publishSigned
- 9. make a separate clone of the repo in another directory and
- check out the gh-pages branch
- 10. /bin/rm -rf latest/api on gh-pages checkout
- 11. copy config/target/api from master checkout to vX.Y.Z in
- gh-pages so you have vX.Y.Z/index.html
- 12. copy config/target/api from master checkout into latest/
- so you have latest/api/index.html
- 13. commit all that to gh-pages, check the diff for sanity
- (latest/api should be mostly just changed timestamps)
- 14. push gh-pages
- 15. log into sonatype website and go through the usual hoops
- (under Staging Repositories, search for com.typesafe, verify the
- artifacts in it, close, release)
- 16. push the "vX.Y.Z" tag
- 17. announce release, possibly wait for maven central to sync
- first
+See RELEASING.md
diff --git a/NEWS.md b/NEWS.md
index 3dffc59e9..aeb66d0d5 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,10 @@
+# 1.4.0: October 11, 2019
+
+- `application.conf` variables can now override variables in `reference.conf` [#619](https://github.com/lightbend/config/issues/167)
+- performance improvement through capacity hint for `ArrayList` [#648](https://github.com/lightbend/config/pull/648)
+
+(This was previously published as 1.3.5-RC1 but deemed a large enough change to require a minor version rather than a patch)
+
# 1.3.4: April 18, 2019
- it is now possible to override any configuration setting from environment variables ([#620](/../../pull/620)) thanks to [@andreaTP](https://github.com/andreaTP)
diff --git a/README.md b/README.md
index 5f24a47c1..e2f29a466 100644
--- a/README.md
+++ b/README.md
@@ -105,12 +105,12 @@ You can find published releases on Maven Central.
com.typesafeconfig
- 1.3.4
+ 1.4.0
sbt dependency:
- libraryDependencies += "com.typesafe" % "config" % "1.3.4"
+ libraryDependencies += "com.typesafe" % "config" % "1.4.0"
Link for direct download if you don't use a dependency manager:
diff --git a/RELEASING.md b/RELEASING.md
new file mode 100644
index 000000000..08d4723b1
--- /dev/null
+++ b/RELEASING.md
@@ -0,0 +1,37 @@
+# Making a release
+
+To make a release you'll need to be a maintainer with GitHub
+permissions to push to the master and gh-pages branches, and
+Sonatype permissions to publish.
+
+Here are the steps, which should be automated but aren't (PR
+welcome!):
+
+ 1. write release notes in NEWS.md following the format
+ already in there. update README with the new version.
+ Commit.
+ 2. create a signed git tag "vX.Y.Z"
+ 3. start sbt; `show version` should confirm that the version was
+ taken from the tag
+ 4. clean
+ 5. test (double check that release works)
+ 6. doc (double check that docs build, plus build docs
+ to be copied to gh-pages later)
+ 7. if test or doc fails, delete the tag, fix it, start over.
+ 8. publishSigned
+ 9. make a separate clone of the repo in another directory and
+ check out the gh-pages branch
+ 10. /bin/rm -rf latest/api on gh-pages checkout
+ 11. copy config/target/api from master checkout to vX.Y.Z in
+ gh-pages so you have vX.Y.Z/index.html
+ 12. copy config/target/api from master checkout into latest/
+ so you have latest/api/index.html
+ 13. commit all that to gh-pages, check the diff for sanity
+ (latest/api should be mostly just changed timestamps)
+ 14. push gh-pages
+ 15. log into sonatype website and go through the usual hoops
+ (under Staging Repositories, search for com.typesafe, verify the
+ artifacts in it, close, release)
+ 16. push the "vX.Y.Z" tag
+ 17. announce release, possibly wait for maven central to sync
+ first
diff --git a/build.sbt b/build.sbt
index 8a6b87f78..631d5c8d9 100644
--- a/build.sbt
+++ b/build.sbt
@@ -4,7 +4,7 @@
// Release tags should follow: http://semver.org/
import scalariform.formatter.preferences._
-ThisBuild / git.baseVersion := "1.3.0"
+ThisBuild / git.baseVersion := "1.4.0"
ThisBuild / organization := "com.typesafe"
ThisBuild / Compile / scalacOptions := List("-unchecked", "-deprecation", "-feature")
ThisBuild / Test / scalacOptions := List("-unchecked", "-deprecation", "-feature")
From 1ba4ed8cbaa76af911e0b5d854cb93eff1743e55 Mon Sep 17 00:00:00 2001
From: Christian Wiech
Date: Sun, 8 Dec 2019 11:07:30 +0100
Subject: [PATCH 80/83] Make Optional inheritable (references #659)
---
config/src/main/java/com/typesafe/config/Optional.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/config/src/main/java/com/typesafe/config/Optional.java b/config/src/main/java/com/typesafe/config/Optional.java
index 4645ed5fb..5498b8f41 100644
--- a/config/src/main/java/com/typesafe/config/Optional.java
+++ b/config/src/main/java/com/typesafe/config/Optional.java
@@ -1,6 +1,7 @@
package com.typesafe.config;
import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -8,6 +9,7 @@
* Allows an config property to be {@code null}.
*/
@Documented
+@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Optional {
From 90103f02ebaf8bf55b0e725fc4732b72b6ab2cbc Mon Sep 17 00:00:00 2001
From: Christian Wiech
Date: Sun, 8 Dec 2019 11:10:52 +0100
Subject: [PATCH 81/83] Evaluate getter for optional annotation if field exists
(references #659)
---
.../typesafe/config/impl/ConfigBeanImpl.java | 48 ++++++++++++-------
1 file changed, 30 insertions(+), 18 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
index 2b9cf5c60..c434b9a22 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
@@ -27,21 +27,22 @@
import com.typesafe.config.Optional;
/**
- * Internal implementation detail, not ABI stable, do not touch.
- * For use only by the {@link com.typesafe.config} package.
+ * Internal implementation detail, not ABI stable, do not touch. For use only by
+ * the {@link com.typesafe.config} package.
*/
public class ConfigBeanImpl {
/**
- * This is public ONLY for use by the "config" package, DO NOT USE this ABI
- * may change.
- * @param type of the bean
+ * This is public ONLY for use by the "config" package, DO NOT USE this ABI may
+ * change.
+ *
+ * @param type of the bean
* @param config config to use
- * @param clazz class of the bean
+ * @param clazz class of the bean
* @return the bean instance
*/
public static T createInternal(Config config, Class clazz) {
- if (((SimpleConfig)config).root().resolveStatus() != ResolveStatus.RESOLVED)
+ if (((SimpleConfig) config).root().resolveStatus() != ResolveStatus.RESOLVED)
throw new ConfigException.NotResolved(
"need to Config#resolve() a config before using it to initialize a bean, see the API docs for Config#resolve()");
@@ -126,9 +127,11 @@ public static T createInternal(Config config, Class clazz) {
}
return bean;
} catch (InstantiationException e) {
- throw new ConfigException.BadBean(clazz.getName() + " needs a public no-args constructor to be used as a bean", e);
+ throw new ConfigException.BadBean(
+ clazz.getName() + " needs a public no-args constructor to be used as a bean", e);
} catch (IllegalAccessException e) {
- throw new ConfigException.BadBean(clazz.getName() + " getters and setters are not accessible, they must be for use as a bean", e);
+ throw new ConfigException.BadBean(
+ clazz.getName() + " getters and setters are not accessible, they must be for use as a bean", e);
} catch (InvocationTargetException e) {
throw new ConfigException.BadBean("Calling bean method on " + clazz.getName() + " caused an exception", e);
}
@@ -141,7 +144,7 @@ public static T createInternal(Config config, Class clazz) {
// of a nicer error message giving the name of the bad
// setting. So, instead, we only support a limited number of
// types plus you can always use Object, ConfigValue, Config,
- // ConfigObject, etc. as an escape hatch.
+ // ConfigObject, etc. as an escape hatch.
private static Object getValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config,
String configPropName) {
if (parameterClass == Boolean.class || parameterClass == boolean.class) {
@@ -166,9 +169,11 @@ private static Object getValue(Class> beanClass, Type parameterType, Class>
return getSetValue(beanClass, parameterType, parameterClass, config, configPropName);
} else if (parameterClass == Map.class) {
// we could do better here, but right now we don't.
- Type[] typeArgs = ((ParameterizedType)parameterType).getActualTypeArguments();
+ Type[] typeArgs = ((ParameterizedType) parameterType).getActualTypeArguments();
if (typeArgs[0] != String.class || typeArgs[1] != Object.class) {
- throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class " + beanClass.getName() + " has unsupported Map<" + typeArgs[0] + "," + typeArgs[1] + ">, only Map is supported right now");
+ throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class "
+ + beanClass.getName() + " has unsupported Map<" + typeArgs[0] + "," + typeArgs[1]
+ + ">, only Map is supported right now");
}
return config.getObject(configPropName).unwrapped();
} else if (parameterClass == Config.class) {
@@ -186,16 +191,19 @@ private static Object getValue(Class> beanClass, Type parameterType, Class>
} else if (hasAtLeastOneBeanProperty(parameterClass)) {
return createInternal(config.getConfig(configPropName), parameterClass);
} else {
- throw new ConfigException.BadBean("Bean property " + configPropName + " of class " + beanClass.getName() + " has unsupported type " + parameterType);
+ throw new ConfigException.BadBean("Bean property " + configPropName + " of class " + beanClass.getName()
+ + " has unsupported type " + parameterType);
}
}
- private static Object getSetValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config, String configPropName) {
+ private static Object getSetValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config,
+ String configPropName) {
return new HashSet((List) getListValue(beanClass, parameterType, parameterClass, config, configPropName));
}
- private static Object getListValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config, String configPropName) {
- Type elementType = ((ParameterizedType)parameterType).getActualTypeArguments()[0];
+ private static Object getListValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config,
+ String configPropName) {
+ Type elementType = ((ParameterizedType) parameterType).getActualTypeArguments()[0];
if (elementType == Boolean.class) {
return config.getBooleanList(configPropName);
@@ -231,7 +239,8 @@ private static Object getListValue(Class> beanClass, Type parameterType, Class
}
return beanList;
} else {
- throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class " + beanClass.getName() + " has unsupported list element type " + elementType);
+ throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class " + beanClass.getName()
+ + " has unsupported list element type " + elementType);
}
}
@@ -285,7 +294,10 @@ private static boolean hasAtLeastOneBeanProperty(Class> clazz) {
private static boolean isOptionalProperty(Class beanClass, PropertyDescriptor beanProp) {
Field field = getField(beanClass, beanProp.getName());
- return field != null ? field.getAnnotationsByType(Optional.class).length > 0 : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
+ return field != null
+ ? field.getAnnotationsByType(Optional.class).length > 0
+ || beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0
+ : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
}
private static Field getField(Class beanClass, String fieldName) {
From f3b6eca379d216b8bb0b75844f4693144afb0986 Mon Sep 17 00:00:00 2001
From: Christian Wiech
Date: Sun, 8 Dec 2019 11:25:08 +0100
Subject: [PATCH 82/83] Revert "Evaluate getter for optional annotation if
field exists (references #659) beacuse of accidently used code formatter"
This reverts commit eafb1d84cbd48a1c378904a088c3992b6c2992ce.
---
.../typesafe/config/impl/ConfigBeanImpl.java | 48 +++++++------------
1 file changed, 18 insertions(+), 30 deletions(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
index c434b9a22..2b9cf5c60 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
@@ -27,22 +27,21 @@
import com.typesafe.config.Optional;
/**
- * Internal implementation detail, not ABI stable, do not touch. For use only by
- * the {@link com.typesafe.config} package.
+ * Internal implementation detail, not ABI stable, do not touch.
+ * For use only by the {@link com.typesafe.config} package.
*/
public class ConfigBeanImpl {
/**
- * This is public ONLY for use by the "config" package, DO NOT USE this ABI may
- * change.
- *
- * @param type of the bean
+ * This is public ONLY for use by the "config" package, DO NOT USE this ABI
+ * may change.
+ * @param type of the bean
* @param config config to use
- * @param clazz class of the bean
+ * @param clazz class of the bean
* @return the bean instance
*/
public static T createInternal(Config config, Class clazz) {
- if (((SimpleConfig) config).root().resolveStatus() != ResolveStatus.RESOLVED)
+ if (((SimpleConfig)config).root().resolveStatus() != ResolveStatus.RESOLVED)
throw new ConfigException.NotResolved(
"need to Config#resolve() a config before using it to initialize a bean, see the API docs for Config#resolve()");
@@ -127,11 +126,9 @@ public static T createInternal(Config config, Class clazz) {
}
return bean;
} catch (InstantiationException e) {
- throw new ConfigException.BadBean(
- clazz.getName() + " needs a public no-args constructor to be used as a bean", e);
+ throw new ConfigException.BadBean(clazz.getName() + " needs a public no-args constructor to be used as a bean", e);
} catch (IllegalAccessException e) {
- throw new ConfigException.BadBean(
- clazz.getName() + " getters and setters are not accessible, they must be for use as a bean", e);
+ throw new ConfigException.BadBean(clazz.getName() + " getters and setters are not accessible, they must be for use as a bean", e);
} catch (InvocationTargetException e) {
throw new ConfigException.BadBean("Calling bean method on " + clazz.getName() + " caused an exception", e);
}
@@ -144,7 +141,7 @@ public static T createInternal(Config config, Class clazz) {
// of a nicer error message giving the name of the bad
// setting. So, instead, we only support a limited number of
// types plus you can always use Object, ConfigValue, Config,
- // ConfigObject, etc. as an escape hatch.
+ // ConfigObject, etc. as an escape hatch.
private static Object getValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config,
String configPropName) {
if (parameterClass == Boolean.class || parameterClass == boolean.class) {
@@ -169,11 +166,9 @@ private static Object getValue(Class> beanClass, Type parameterType, Class>
return getSetValue(beanClass, parameterType, parameterClass, config, configPropName);
} else if (parameterClass == Map.class) {
// we could do better here, but right now we don't.
- Type[] typeArgs = ((ParameterizedType) parameterType).getActualTypeArguments();
+ Type[] typeArgs = ((ParameterizedType)parameterType).getActualTypeArguments();
if (typeArgs[0] != String.class || typeArgs[1] != Object.class) {
- throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class "
- + beanClass.getName() + " has unsupported Map<" + typeArgs[0] + "," + typeArgs[1]
- + ">, only Map is supported right now");
+ throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class " + beanClass.getName() + " has unsupported Map<" + typeArgs[0] + "," + typeArgs[1] + ">, only Map is supported right now");
}
return config.getObject(configPropName).unwrapped();
} else if (parameterClass == Config.class) {
@@ -191,19 +186,16 @@ private static Object getValue(Class> beanClass, Type parameterType, Class>
} else if (hasAtLeastOneBeanProperty(parameterClass)) {
return createInternal(config.getConfig(configPropName), parameterClass);
} else {
- throw new ConfigException.BadBean("Bean property " + configPropName + " of class " + beanClass.getName()
- + " has unsupported type " + parameterType);
+ throw new ConfigException.BadBean("Bean property " + configPropName + " of class " + beanClass.getName() + " has unsupported type " + parameterType);
}
}
- private static Object getSetValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config,
- String configPropName) {
+ private static Object getSetValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config, String configPropName) {
return new HashSet((List) getListValue(beanClass, parameterType, parameterClass, config, configPropName));
}
- private static Object getListValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config,
- String configPropName) {
- Type elementType = ((ParameterizedType) parameterType).getActualTypeArguments()[0];
+ private static Object getListValue(Class> beanClass, Type parameterType, Class> parameterClass, Config config, String configPropName) {
+ Type elementType = ((ParameterizedType)parameterType).getActualTypeArguments()[0];
if (elementType == Boolean.class) {
return config.getBooleanList(configPropName);
@@ -239,8 +231,7 @@ private static Object getListValue(Class> beanClass, Type parameterType, Class
}
return beanList;
} else {
- throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class " + beanClass.getName()
- + " has unsupported list element type " + elementType);
+ throw new ConfigException.BadBean("Bean property '" + configPropName + "' of class " + beanClass.getName() + " has unsupported list element type " + elementType);
}
}
@@ -294,10 +285,7 @@ private static boolean hasAtLeastOneBeanProperty(Class> clazz) {
private static boolean isOptionalProperty(Class beanClass, PropertyDescriptor beanProp) {
Field field = getField(beanClass, beanProp.getName());
- return field != null
- ? field.getAnnotationsByType(Optional.class).length > 0
- || beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0
- : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
+ return field != null ? field.getAnnotationsByType(Optional.class).length > 0 : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
}
private static Field getField(Class beanClass, String fieldName) {
From 050cdb6bf7f51df9a5334312dd8cb32a2e96f1b0 Mon Sep 17 00:00:00 2001
From: Christian Wiech
Date: Sun, 8 Dec 2019 11:27:57 +0100
Subject: [PATCH 83/83] Evaluate getter for optional annotation if field exists
(references #659)
---
.../main/java/com/typesafe/config/impl/ConfigBeanImpl.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
index 2b9cf5c60..902311359 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigBeanImpl.java
@@ -285,7 +285,10 @@ private static boolean hasAtLeastOneBeanProperty(Class> clazz) {
private static boolean isOptionalProperty(Class beanClass, PropertyDescriptor beanProp) {
Field field = getField(beanClass, beanProp.getName());
- return field != null ? field.getAnnotationsByType(Optional.class).length > 0 : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
+ return field != null
+ ? field.getAnnotationsByType(Optional.class).length > 0
+ || beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0
+ : beanProp.getReadMethod().getAnnotationsByType(Optional.class).length > 0;
}
private static Field getField(Class beanClass, String fieldName) {