Frage

I need to get a Java enum value from a string given Enum's Class instance. I tried code like below, but I'm getting "unbound wildcard type" compilation error. Seems, I need to do something with existential types, forSome {} or something, but I can't get how to do it right.

val paramClass = method.getParameterTypes()(0)
val value = paramClass match {
  case _ if classOf[Enum[_]].isAssignableFrom(paramClass) => Enum.valueOf[_ <: Enum[_]](paramClass.asInstanceOf[Class[_ <: Enum[_]]], "MYENUM")
War es hilfreich?

Lösung

Hmm, tough one. I have a working solution, but I find it ugly. I'll be interested in any more elegant approach!

def enumValueOf[T <: Enum[T]](cls: Class[_], stringValue: String): Enum[_] =
  Enum.valueOf(cls.asInstanceOf[Class[T]], stringValue).asInstanceOf[Enum[_]]

val value = paramClass match {
  case _ if classOf[Enum[_]].isAssignableFrom(paramClass) => enumValueOf(paramClass, "MYENUM")
  case _ => // other cases
}

The reason why I think we need this complexity…

We need the compiler to believe that the Class[_] we have is actually a Class[T <: Enum[T]] (so of course, a preliminary test that this is indeed a Java enum — as done in your code — is needed). So we cast cls to Class[T], where T was inferred by the compiler to be <: Enum[T]. But the compiler still has to find a suitable T, and defaults to Nothing here. So, as far as the compiler is concerned, cls.asInstanceOf[Class[T]] is a Class[Nothing]. This is temporarily OK since it can be used to call Enum.valueOf — the problem is that the inferred return type of valueOf is then, naturally, Nothing as well. And here we have a problem, because the compiler will insert an exception when we try to actually use an instance of type Nothing. So, we finally cast the return value of valueOf to an Enum[_].

The trick is then to always let the compiler infer the type argument to enumValueOf and never try to specify it ourselves (since we're not supposed to know it anyway) — and thus to extract the call to Enum.valueOf in another method, giving the compiler a chance to bind a T <: Enum[T].

As I said, I'm not very happy with this solution, which looks way more complicated than it should be…

Update: I've simplified the code slightly.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top