Search code examples
scalapureconfig

Pureconfig error: Cannot find an implicit instance of pureconfig.ConfigReader[A]


I'm building a librairy to give access to several catalog of data. A catalog can refer to a database and the associated tables defined in configuration files (HOCON). Here is a config file example (book.conf):

author {
  database = "db_books"
  table = "author"
}

book {
  database = "db_books"
  table = "book"
}

I define a case class representing this config file (BookCatalogConfig.scala):

trait CatalogConfig

case class TableConfig(database: String, table: String)

case class BookCatalogConfig(author: TableConfig, book: TableConfig) extends CatalogConfig

Then I define my BookCatalog like that:

case class BookCatalog(environment: String) {
  /* ... */
  val config: BookCatalogConfig = CatalogConfigLoader[BookCatalogConfig](environment).load()
  /* ... */
}

And my CatalogConfigLoader utility:

case class CatalogConfigLoader[A <: CatalogConfig](environment: String) {
  def load(): A = {
    import pureconfig.generic.auto._
    // Note: ConfigHelper.getConfig(environment) return a Typesafe Config object with the content of book.conf)
    ConfigSource.fromConfig(ConfigHelper.getConfig(environment)).load[A] match {
      case Right(catalogConfig: A) => catalogConfig
      case Left(error: ConfigReaderFailures) => throw new Exception(error.toString())
    }
  }
}

But this doesn't compile with an error: Cannot find an implicit instance of pureconfig.ConfigReader[A]. If you are trying to read or write a case class or sealed trait consider using PureConfig's auto derivation by adding import pureconfig.generic.auto._

I've already read a lot on the subject, but no solution has worked

Note: I'm using Pureconfig 0.14 for scala 2.11 (I cannot upgade because 0.14 is the last one for scala 2.11... and I cannot upgrade the scala version too...).


Solution

  • The solution is (thanks to Luis Miguel and Matthias), with some rework:

    object CatalogConfigLoader {
      def load[A <: CatalogConfig : ConfigReader : ClassTag](environment: Environment): A = {    
      ConfigSource.fromConfig(ConfigHelper.getConfig(environment.filepath)).load[A] match {
        case Right(catalogConfig: A) => catalogConfig
        case Left(error: ConfigReaderFailures) => throw new Exception(error.toString())
      }
    }