Implementing Config class containing Enum Map by PureConfig and Enumeratum

574 Views Asked by At

I'm trying to read my config file into my case class whose one of attribute is a Map of Enumeratum key and Case Class value by using pureconfig and pureconfig-enumeratum libraries version 0.14.0 with scala 2.11. When I change the Map key from Enumeratum key to String, it works, but it does not work with Enum key.

import enumeratum.EnumEntry.{Hyphencase}
import enumeratum._
import pureconfig.{ConfigSource}
import pureconfig.generic.auto._
import pureconfig.module.enumeratum._ 

object CheckPureConfig extends App {
      
      private val myConf = ConfigSource.default.loadOrThrow[SsystemConf]
      println(myConf)
    }
    
    case class SsystemConf(target: Map[Ssystem, MyConfig])
    case class MyConfig(path: Ssystem, link: String)
    
    sealed abstract class Ssystem(myField: String) extends EnumEntry with Hyphencase{
      def printit() = myField
    }
    object Ssystem extends Enum[Ssystem] {
      val values = findValues
    
      case object MyEnumA extends Ssystem("testFieldEnum1")
      case object MyEnumB extends Ssystem("testFieldEnum2")
    }

And this is my application.conf

target {
   my-enum-a= {
      path : "samplepath1"
      link : "samplehttp1"
    }
    my-enum-b = {
          path : "samplepath2"
          link : "samplehttp2"
    }
}
2

There are 2 best solutions below

0
On BEST ANSWER

You have to use configurable converter to tell pureconfig how to transform your enum to Map keys. You have genericMapReader for that:

implicit def enumMapReader[V: ConfigReader]: ConfigReader[Map[Ssystem, V]] =
  genericMapReader { name =>
    Ssystem.withNameOption(name)
      .fold[Either[String, Ssystem]](Left(s"$name is not enum"))(Right(_))
  }
0
On

Just building on @mateusz-kubuszok answer, this is what worked for me for version 0.17.6.

Here my map key enum class is called TriggerSource

implicit def enumMapReader[V: ConfigReader]: ConfigReader[Map[TriggerSource, V]] =
    genericMapReader[TriggerSource, V] { name =>
      TriggerSource.withNameOption(name) match {
        case Some(value) => Right(value)
        case None        => Left(CannotConvert(name, "TriggerSource", s"$name is not enum"))
      }
    }