2

I've got a list of case objects of the same type, eg.

object Countries {
    sealed abstract class Country (val name: String)
    case object SE extends Country("Sweden")
    case object AE extends Country("United Arab Emirates")
    case object GB extends Country("United Kingdom")
    case object US extends Country("United States of America")
}

Now I want to create a mapping like this.

val map = Map[String, Country](

        CH.name -> CH,
        AE.name -> AE,
        GB.name -> GB,
        US.name -> US

        )

So that I can do this ie. get a reference to the appropriate case object by passing it's String key.

val us = Countries.map.get("United Kingdom")

Is there a way to automatically generate the map ?

JamieP
  • 1,664
  • 2
  • 13
  • 16

1 Answers1

2
object ReflectUtils {
  import scala.reflect.runtime.universe.{TypeTag, typeOf}

  def knownDirectSubclassesAsMap[T: TypeTag](keyGenerator: T => String): Map[String, T] =
    typeOf[T].typeSymbol.asClass.knownDirectSubclasses.map { c =>
      reflect.runtime.currentMirror.reflectModule(c.owner.typeSignature.member(c.name.toTermName).asModule).instance
    }.asInstanceOf[Set[T]].map(obj => keyGenerator(obj) -> obj).toMap
}

and then:

object Countries {
  sealed abstract class Country(val name: String)
  case object SE extends Country("Sweden")
  case object AE extends Country("United Arab Emirates")
  case object GB extends Country("United Kingdom")
  case object US extends Country("United States of America")

  lazy val countriesByName = ReflectUtils.knownDirectSubclassesAsMap[Country](_.name)
  def forName = countriesByName.apply _
}

e. g. Countries.forName("United States of America") returns Countries.US object.

TeWu
  • 5,928
  • 2
  • 22
  • 36