2

I use double to encode boolean value in a configuration file. PureConfig does not find a way to cast it while reading the configuration.


Initial question (see below for edit).

Here is some code to reproduce the behavior.

import com.typesafe.config.ConfigFactory
import pureconfig.ConfigReader
import pureconfig.generic.auto._

object Main {
  def main(args: Array[String]): Unit = {
    println(pureconfig.loadConfig[BooleanTest](ConfigFactory.parseString("a = 1")))
  }
}

case class BooleanTest(a: Boolean)

object ConfigImplicits {
  implicit val myBooleanReader: ConfigReader[Boolean] = ConfigReader[Double].map { n => n > 0}
}

Here, I expect my code to print an instance of BooleanTest. Instead, I got a ConvertFailure:

Left(ConfigReaderFailures(ConvertFailure(WrongType(NUMBER,Set(BOOLEAN)),None,a),List()))

One way to fix this, is to add import ConfigImplicits._ just before calling the loadConfig function. However, as you can suppose, my code is actually part of a bigger project, and adding the import in the real project does not fix my error.

Do you have any hint on what can be wrong?

Kind, Alexis.


Edit:

After comments from Thilo it appears logic to add the import statement.

Below is an updated version of the code which include the import statement but still produce the same error...

Change the main function to:

def main(args: Array[String]): Unit = {
  println(ConfigUtils.loadConfig[BooleanTest]("a = 1"))
}

And declare a ConfigUtils object as follow:

object ConfigUtils {
  def loadConfig[A : ConfigReader](str: String) : ConfigReader.Result[A] = {
    import ConfigImplicits._
    val config = ConfigFactory.parseString(str)
    pureconfig.loadConfig[A](config)
  }
}

Run the code and you get the same error as previously: ConvertFailure(WrongType(NUMBER,Set(BOOLEAN))

Why does pureconfig not use my implicit myBooleanReader to parse this configuration?

Kind, Alexis.

AlexisBRENON
  • 2,921
  • 2
  • 18
  • 30
  • Why does adding the import in the real project not fix the error? How is it supposed to find the implicit if you do not import it? – Thilo May 23 '19 at 08:33
  • The implicit is declared in the same file (as an implicit object inside an object). Why it does not fix the error is a real mystery ! – AlexisBRENON May 23 '19 at 08:45
  • The implicit is declared inside of `ConfigImplicits`. You want to use it inside of `Main`. These are two separate objects. Unless you do something (like an `import`) the implicit is not in scope in `Main`. – Thilo May 23 '19 at 09:10
  • Well, this seems logical, but it does not explain why it does not work in bigger project. I will try to reproduce the bug with small code... – AlexisBRENON May 23 '19 at 09:19
  • You have some indirection here, maybe that is the problem in your bigger project. You need a `ConfigReader[BooleanTest]`. That one is automagically created by the `auto._`. It in turn needs a `ConfigReader[Boolean]`. Without your implicit, it will just read booleans the normal way. So you need to have your implicit ready where the `ConfigReader[BooleanTest]` is created (not where it is used!). – Thilo May 23 '19 at 09:27
  • 1
    Personally I find this setup too fragile and would generally also follow Convention over Configuration. Do not have code that converts Double into Boolean behind the scenes. Either put `true/false` into your config file (much preferred) or read it as a Double and have some `def aBoolean` on your case class to convert it. The ConfigReader should just read the file, not do weird transformations. – Thilo May 23 '19 at 09:28
  • ... or if you really must, make a new type `BooleanDouble`. That way, at least you get compile-time errors when the implicit reader is missing (instead of the default reader for boolean and run-time errors when it sees a number instead of boolean). – Thilo May 23 '19 at 09:32
  • You need to have your implicit visible at the call-site of `ConfigUtils.loadConfig[BooleanTest]`. Not in your `ConfigUtils`. Read up on how the `pureconfig.generic.auto._` works. Or really: Don't try to change how booleans are read. Too fragile/confusing. – Thilo May 23 '19 at 09:36

0 Answers0