Retrieving Scala enumeration constants by name

In many cases you may need to get an enumeration constant by it’s name. It is very easy to do it if you extend the standard Scala Enumeration class to create your enumeration. Below is a typical enumeration implementation:

object FunninessLevel extends Enumeration {
  type FunninessLevel = Value
  val LOL, ROFL, LMAO = Value
}

To retrieve a constant by it’s name you simply call withName on the object:

val level = FunninessLevel.withName("LOL")

So far so good?

It gets more difficult if you need to retrieve a constant for any given enumeration type at run time (e.g. JSON serialization). Java has a very convenient way of doing it: Enum.valueOf. But I could find nothing like that for Scala. So I ended up building my own helpers.

import scala.reflect.runtime.universe._

/**
 * Scala [[Enumeration]] helpers implementing Scala versions of
 * Java's [[java.lang.Enum.valueOf(Class[Enum], String)]].
 * @author Dmitriy Yefremov
 */
object EnumReflector {

  private val mirror: Mirror = runtimeMirror(getClass.getClassLoader)

  /**
   * Returns a value of the specified enumeration with the given name.
   * @param name value name
   * @tparam T enumeration type
   * @return enumeration value, see [[scala.Enumeration.withName(String)]]
   */
  def withName[T <: Enumeration#Value: TypeTag](name: String): T = {
    typeOf[T] match {
      case valueType @ TypeRef(enumType, _, _) =>
        val methodSymbol = factoryMethodSymbol(enumType)
        val moduleSymbol = enumType.termSymbol.asModule
        reflect(moduleSymbol, methodSymbol)(name).asInstanceOf[T]
    }
  }

  /**
   * Returns a value of the specified enumeration with the given name.
   * @param clazz enumeration class
   * @param name value name
   * @return enumeration value, see [[scala.Enumeration#withName(String)]]
   */
  def withName(clazz: Class[_], name: String): Enumeration#Value = {
    val classSymbol = mirror.classSymbol(clazz)
    val methodSymbol = factoryMethodSymbol(classSymbol.toType)
    val moduleSymbol = classSymbol.companionSymbol.asModule
    reflect(moduleSymbol, methodSymbol)(name).asInstanceOf[Enumeration#Value]
  }

  private def factoryMethodSymbol(enumType: Type): MethodSymbol = {
    enumType.member(newTermName("withName")).asMethod
  }

  private def reflect(module: ModuleSymbol, method: MethodSymbol)(args: Any*): Any = {
    val moduleMirror = mirror.reflectModule(module)
    val instanceMirror = mirror.reflect(moduleMirror.instance)
    instanceMirror.reflectMethod(method)(args:_*)
  }

}

Here is a client code example using TypeTag:

val level = EnumReflector.withName[FunninessLevel.Value]("LOL")

And another example with a class instance:

val level = EnumReflector.withName(FunninessLevel.getClass, "ROFL")

I’m quite happy with the TypeTag based implementation. For the class based implementation I would prefer to use classOf[FunninessLevel.Value], but it seems it is impossible. There is no specific value class created for different enumeration types. So classOf[FunninessLevel.Value] returns a reference to the base Enumeration#Value class and there is no way to get a reference to the actual enumeration object.

Do you have any suggestion on how to improve this code?

Written on October 29, 2014