I have a HOCON config like this:
[
{
name = 1
url = "http://example.com"
},
{
name = 2
url = "http://example2.com"
},
{
name = 3
url = {
A = "http://example3.com"
B = "http://example4.com"
}
}
]
I want to parse it with pureconfig. How can I represent that the URL can be either a string or a map of multiple urls, each having a key?
I have tried this:
import pureconfig.ConfigSource
import pureconfig.generic.auto.exportReader
case class Site(name: Int, url: Either[String, Map[String, String]])
case class Config(sites: List[Site])
ConfigSource.default.loadOrThrow[Config]
But it resulted in "Expected type OBJECT. Found STRING instead."
I know pureconfig supports Option
. I have found no mention of supporting Either
, does it mean it can be replaced with something else?
As you can see Either
in not on list of types supported out of the box.
However Either
falls under sealed family, so:
@ ConfigSource.string("""{ type: left, value: "test" }""").load[Either[String, String]]
res15: ConfigReader.Result[Either[String, String]] = Right(Left("test"))
@ ConfigSource.string("""{ type: right, value: "test" }""").load[Either[String, String]]
res16: ConfigReader.Result[Either[String, String]] = Right(Right("test"))
works. If you have a sealed hierarchy, what pureconfig will do is require an object which has a field type
- this field will be used to dispatch parsing to a specific subtype. All the other fields will be passed as fields to parse into that subtype.
If that doesn't work for you, you might try to implement the codec yourself:
// just an example
implicit def eitherReader[A: ConfigReader, B: ConfigReader] =
new ConfigReader[Either[A, B]] {
def from(cur: ConfigCursor) =
// try left, if fail try right
ConfigReader[A].from(cur).map(Left(_)) orElse ConfigReader[B].from(cur).map(Right(_))
}
which now will not require discrimination value:
@ ConfigSource.string("""{ test: "test" }""").load[Map[String, Either[String, String]]]
res26: ConfigReader.Result[Map[String, Either[String, String]]] = Right(Map("test" -> Left("test")))
This is not provided by default because you would have to answer a few things yourself:
Left
or Right
decoding?Left
fallback Right
or Right
fallback Left
make sense?Either[X, X]
?If you have an idea what is expected behavior you can implement your own codec and use it in derivation.