Stack Exchange
Can't get pureconfig to deserialize nested case classes
I'm trying to get nested case classes to deserialize with pureconfig, but the code fails to compile. I have something as follows:
import com.typesafe.config.{Config, ConfigFactory}
import pureconfig.error.ConfigReaderFailures
import pureconfig.generic.ProductHint
import pureconfig.generic.semiauto._
import pureconfig.{CamelCase, ConfigFieldMapping}

class ClassAReader {
  implicit def classAHint = ProductHint[ClassA](ConfigFieldMapping(CamelCase, CamelCase))
  implicit def classBHint = ProductHint[ClassB](ConfigFieldMapping(CamelCase, CamelCase))

  implicit val classAReader = deriveReader[ClassA]
  implicit val classBReader = deriveReader[ClassB]

  def read(config: Config): ClassA = pureconfig.loadConfig[ClassA](config.getConfig("foo")).fold((a: ConfigReaderFailures) => throw new Exception(), conf => conf)

  val config = ConfigFactory.parseString("""{ a: { one: 1, two: "foo" }, b: { one: 2, two: "bar" }, 42 }""")
  val reader = new ClassAReader

  reader.read(config)
}

case class ClassA(a: ClassB, b: ClassB, other: Int)

case class ClassB(one: Int, two: String)

But I'm getting compilation issues. Anyone know what I'm doing wrong?

You should always annotate implicit definitions, especially in situations like this, where the derivation of the reader for ClassA depends on the one for ClassB, etc. The following just works:
import com.typesafe.config.{Config, ConfigFactory}
import pureconfig.ConfigReader
import pureconfig.error.ConfigReaderFailures
import pureconfig.generic.ProductHint
import pureconfig.generic.semiauto._
import pureconfig.{CamelCase, ConfigFieldMapping}

class ClassAReader {
  implicit def classAHint: ProductHint[ClassA] =
    ProductHint[ClassA](ConfigFieldMapping(CamelCase, CamelCase))
  implicit def classBHint: ProductHint[ClassB] =
    ProductHint[ClassB](ConfigFieldMapping(CamelCase, CamelCase))

  implicit val classAReader: ConfigReader[ClassA] = deriveReader[ClassA]
  implicit val classBReader: ConfigReader[ClassB] = deriveReader[ClassB]

  def read(config: Config): Either[ConfigReaderFailures, ClassA] =
    pureconfig.loadConfig[ClassA](config)
}

case class ClassA(a: ClassB, b: ClassB, other: Int)
case class ClassB(one: Int, two: String)

And then:
scala> val config = ConfigFactory.parseString(
     |   """{ a: { one: 1, two: "foo" }, b: { one: 2, two: "bar" }, other: 42 }"""
     | )
config: com.typesafe.config.Config = Config(SimpleConfigObject({"a":{"one":1,"two":"foo"},"b":{"one":2,"two":"bar"},"other":42}))

scala> val reader = new ClassAReader
reader: ClassAReader = ClassAReader@589da48f

scala> reader.read(config)
res1: Either[pureconfig.error.ConfigReaderFailures,ClassA] = Right(ClassA(ClassB(1,foo),ClassB(2,bar),42))

(Note that I also had to move the read call out of the class—otherwise the constructor is calling itself and you'll get a Stack Overflow. I also fixed the example so it can actually be decoded.)
