Вы должны всегда комментировать неявные определения, особенно в таких ситуациях, когда вывод читателя для ClassA
зависит от вывода для ClassB
и т. Д. Следующее просто работает:
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)
А потом:
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))
(Обратите внимание, что мне также пришлось переместить вызов read
из класса - в противном случае конструктор вызывает сам себя, и вы получите стекПереполнение. Я также исправил пример, чтобы его можно было декодировать.)