Search code examples
scalaconfigtypesafe-config

Typesafe config - parse from map/file and resolve


I can resolve substitutions when I parse config from string, but not when parsing from map or file.

import java.io.File
import com.typesafe.config.{Config, ConfigFactory}
import scala.collection.JavaConversions.mapAsJavaMap

val s: String = "a = test, b = another ${a}"
val m: Map[String, String] = Map("a" -> "test", "b" -> "another ${a}")
val f: File = new File("test.properties") // contains "a = test\nb = another ${a}"

val cs: Config = ConfigFactory.parseString(s).resolve
val cm: Config = ConfigFactory.parseMap(mapAsJavaMap(m)).resolve
val cf: Config = ConfigFactory.parseFile(f).resolve

println("b from string = " + cs.getString("b"))
println("b from map = " + cm.getString("b"))
println("b from file = " + cf.getString("b"))

> b from string = another test
> b from map = another ${a}
> b from file = another ${a}

When I do not resolve immediately it's visible that variable placeholders are not really treated the same way:

val cs: Config = ConfigFactory.parseString(s)
val cm: Config = ConfigFactory.parseMap(mapAsJavaMap(m))
val cf: Config = ConfigFactory.parseFile(f)

> cs: com.typesafe.config.Config = Config(SimpleConfigObject({"a":"test","b":"another "${a}}))
> cm: com.typesafe.config.Config = Config(SimpleConfigObject({"a":"test","b":"another ${a}"}))
> cf: com.typesafe.config.Config = Config(SimpleConfigObject({"a":"test","b":"another ${a}"}))

I could maybe just convert map/file to string, but is there a way to make the library handle it?


Solution

  • The ConfigFactory.parseMap method lead to fromAnyRef, the relevant part for us is:

    if (object instanceof String)
      return new ConfigString.Quoted(origin, (String) object);
    

    It never parses the value as ConfigReference, so there is no way the resolve could work.

    Their rationale could be that if you "control" the data structure then you can, somehow, leverage scala string interpolation.


    For the parseFile the situation is easier. Java properties files does not support ${} substitutions, the type of the file is guessed by the (.properties) file extension.

    You can just use, for instance, the HOCON format: you just have to rename the file (e.g. test.conf), ${} substitutions should then work out-of-the-box.

    More information here: HOCON