scalapureconfig

Decode config to case class with pureconfig with default values


Assuming I have the following config:

{
  “default-value”:5,
  “some-seq”: [
    {“some-other-value”:100},
    {“foo”:”bar”},
    {“some-other-value”:1500}
  ]
}

I want it to be decoded to case classes:

case class Config(defaultValue: Int, someSeq: Seq[SomeInteger])
case class SomeInteger(someOtherValue: Int)

So that it creates Config(5, Seq(SomeInteger(100), SomeInteger(5), SomeInteger(1500))) (Second one is 5 since there is no some-other-value key in the second object of the list) Is there a way to do so?


Solution

  • You can add a type parameter to SomeInteger and Config to specify what the type of someOtherValue should be. Then you create a ConfigReader[Config[Option[Int]]] and use the map method to apply the default:

    case class Config[A](defaultValue: Int, someSeq: Seq[SomeInteger[A]])
    object Config {
      private def applyDefault(config: Config[Option[Int]]): Config[Int] =
        config.copy(
          someSeq = config.someSeq.map(i =>
            i.copy(
              someOtherValue = i.someOtherValue.getOrElse(config.defaultValue))))
    
      implicit val reader: ConfigReader[Config[Int]] =
        deriveReader[Config[Option[Int]]]
          .map(applyDefault)
    }
    case class SomeInteger[A](someOtherValue: A)
    object SomeInteger {
      implicit val reader: ConfigReader[SomeInteger[Option[Int]]] =
        deriveReader[SomeInteger[Option[Int]]]
    }
    

    Unfortunately this means you need to write Config[Int] everywhere instead of just Config. But this can easily be fixed by renaming Config to e. g. GenConfig and add a type alias: type Config = GenConfig[Int].