Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

circe-config will fail on Boolean values written as "on/true/false/off" #12

Open
seigert opened this issue Jan 31, 2018 · 4 comments
Open

Comments

@seigert
Copy link

seigert commented Jan 31, 2018

It may be intended, but right now circe-config is inconsistent with original config for Boolean values written as strings:

scala> import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigFactory

scala> import io.circe.config.parser
import io.circe.config.parser

scala> val config = ConfigFactory.parseString("server { host = localhost, port = 8080 }")
config: com.typesafe.config.Config = Config(SimpleConfigObject({"server":{"host":"localhost","port":8080}}))

scala> val config = ConfigFactory.parseString("server { host = localhost, port = 8080, enabled = on }")
config: com.typesafe.config.Config = Config(SimpleConfigObject({"server":{"enabled":"on","host":"localhost","port":8080}}))

scala> val json: Either[io.circe.ParsingFailure, io.circe.Json] = parser.parse(config)

json: Either[io.circe.ParsingFailure,io.circe.Json] =
Right({
  "server" : {
    "enabled" : "on",
    "port" : 8080,
    "host" : "localhost"
  }
})

scala> config.getBoolean("server.enabled")
res0: Boolean = true

It is possible to work around it, but it is not very convenient when passing config values via ENV_VARIABLES in K8s -- it disallows unquoted strings. :(

@jonas
Copy link
Contributor

jonas commented Feb 1, 2018

The problem is that com.typesafe.config.Config is converted to io.circe.Json without knowing what will be the final type of the "on" string. As far as I know it is not possible to introspect the structure of the type when it is being decoded.

The only solution I can think of is to create a wrapper "boolean' type which allows to use an implicit convertion to translate from string to boolean as Typesafe config does.

import scala.language.implicitConversions
import org.scalatest.{ FlatSpec, Matchers }
import com.typesafe.config.ConfigFactory
import io.circe._
import io.circe.generic.auto._
import io.circe.config.syntax._

object ConfigBooleanSpec {
  case class ConfigBoolean(value: Boolean)
  object ConfigBoolean {
    implicit def toBoolean(b: ConfigBoolean): Boolean = b.value
  }

  implicit val configBooleanDecoder: Decoder[ConfigBoolean] = {
    val truthful = Set("true", "yes", "on")
    Decoder.decodeString.map(s => ConfigBoolean(truthful(s)))
  }

  case class ServerConfig(host: String, port: Int, enabled: ConfigBoolean)
}

class ConfigBooleanSpec extends FlatSpec with Matchers {
  import ConfigBooleanSpec._

  "custom boolean" should "parse and decode from string" in {
    val config = ConfigFactory.parseString(
      """
        host = localhost
        port = 8080
        enabled = on
      """)
    val Right(ServerConfig(_, _, enabled)) = config.as[ServerConfig]
    assert(enabled.value)
    assert(enabled)
  }

}

@jonas
Copy link
Contributor

jonas commented Feb 1, 2018

It would be good to document this though so if you are up for making a PR that would be great else let's keep this issue open until that gets fixed.

@seigert
Copy link
Author

seigert commented Feb 4, 2018

Sorry for the late answer, ConfigBoolean is a possible solution, but it will not work with external/legacy entities with Boolean attributes or providing their own Decoder instance. Or if you just dont want to leak circe-config details in your domain model.

I think better solution would be to delay conversion to Json as much as possible or even do not convert at all, but it would require some kind of JsonDelegate instance that does nothing but delegates fold(..) and asNull|asBoolean|.. methods to it's underlying value. And I don't think it's possible with current circe as Json is sealed.

Maybe something could be done via ConfigCursor version of HCursor for Decoder to use?

@jonas
Copy link
Contributor

jonas commented Feb 16, 2018

I agree that would be optimal but not sure it is possible to do this sort of lazy conversion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants