mardi 15 décembre 2015

How to instantiate a generic class using reflection in scala

I have a class hierarchy beginning with these traits:

sealed trait MessageBody
sealed trait MessageKey[T <: MessageBody]

I need to build automatically a list of all direct subclasses of MessageKey. With searching here and there I came up to this point:

object MessageKey {
  private def sealedDescendants[Root: TypeTag] = {
    val symbol = typeOf[Root].typeSymbol
    val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
    if (internal.isSealed) {
      val symbols = internal.sealedDescendants.map(_.asInstanceOf[Symbol]) - symbol
      val types = internal.sealedDescendants.filter(_.typeSignature.typeConstructor.baseTypeSeq.length > 3).map(_.typeSignature.typeConstructor.baseTypeSeq(3))
      (symbols zip types)
    } else {
      Set.empty
    }
  }
  // set of all keys (i.e., descendants of MessageKey
  private val allClassesAndTypes = sealedDescendants[MessageKey[_ <: MessageBody]]
  // map from key-strings to constructors of the MessageKey
  private val allObjects = (for ((aKey, aType) <- allClassesAndTypes) yield {
    print(aKey+": "+aType)
    val ctor = aKey.typeSignature.declaration(ru.nme.CONSTRUCTOR).asMethod
    val mirror = ru.runtimeMirror(getClass.getClassLoader)
    val cm = mirror.reflectClass(aKey.asClass)
    val ctorm = cm.reflectConstructor(ctor)
    val keyObj: MessageKey[_ <: MessageBody] = ctorm().asInstanceOf[MessageKey[_ <: MessageBody]]
    (keyObj.toString -> ctorm)
  }).toMap
}

This code give me objects with type MessageKey[Nothing]. As you see above, I somehow get to the Type of each key, but I do not know how to use it.

I would like to do something like

    val keyObj: MessageKey[_ <: MessageBody] = ctorm().asInstanceOf[aType]

But, of course, I cannot use aType there just like that. Any help is appreciated.





Aucun commentaire:

Enregistrer un commentaire