Having a following enumeration
object ResponseType extends Enumeration {
val Listing, Album = Value
}
How do I get a list of its vals?
The following code gets a list of Symbol
objects representing the "vals":
import reflect.runtime.universe._ // Access the reflection api
typeOf[ResponseType.Value] // - A `Type`, the basic unit of reflection api
.asInstanceOf[TypeRef] // - A specific kind of Type with knowledge of
// the place it's being referred from
.pre // - AFAIK the referring Type
.members // - A list of `Symbol` objects representing
// all members of this type, including
// private and inherited ones, classes and
// objects - everything.
// `Symbol`s are the second basic unit of
// reflection api.
.view // - For lazy filtering
.filter(_.isTerm) // - Leave only the symbols which extend the
// `TermSymbol` type. This is a very broad
// category of symbols, which besides values
// includes methods, classes and even
// packages.
.filterNot(_.isMethod) // - filter out the rest
.filterNot(_.isModule)
.filterNot(_.isClass)
.toList // - force the view into a final List
It should be noted that instead of filtering on is-clauses it can be implemented with .collect
testing for specific types, like so:
.collect{ case symbol : MethodSymbol => symbol }
This approach may be required for other tasks in the reflection api.
It also should be noted, that using a .view
is not mandatory at all, it just makes using a series of filter
applications (as much as many other functions such as map
, flatMap
and etc.) much more effective, by traversing the input collection only once and at the point where it's actually being forced into some concrete collection (.toList
in our case).
As suggested by Travis Brown, it is also possible to reference the ResponseType
object directly. So the typeOf[ResponseType.Value].asInstanceOf[TypeRef].pre
part can be replaced with typeOf[ResponseType.type]
If you want to be thorough about this, you need to check that your symbols have Value
as a supertype:
def valueSymbols[E <: Enumeration: TypeTag] = {
val valueType = typeOf[E#Value]
typeOf[E].members.filter(sym => !sym.isMethod &&
sym.typeSignature.baseType(valueType.typeSymbol) =:= valueType
)
}
Now even if you have the following (which is perfectly legal):
object ResponseType extends Enumeration {
val Listing, Album = Value
val someNonValueThing = "You don't want this in your list of value symbols!"
}
You still get the correct answer:
scala> valueSymbols[ResponseType.type] foreach println
value Album
value Listing
Your current approach would include value someNonValueThing
here.
You can iterate over the values of an enumeration via the set returned by the enumeration’s values method:
scala> for (e <- ResponseType.values) println(e)
Listing
Album