How to create an instance of type T at runtime with TypeTags

前端 未结 4 407
梦如初夏
梦如初夏 2020-12-24 09:14

Here below is how to create a new instance of type T at runtime with Manifest:

trait MyTrait
class MyClass1(val name: String) extends MyTrait
cl         


        
相关标签:
4条回答
  • 2020-12-24 09:41

    Maybe someone who does this all the time can chime in, but it took me this many steps to reproduce it.

    I start the REPL -i, so autocomplete is broken. That puts me at a disadvantage.

    scala> class X(i: Int)
    defined class X
    
    scala> typeTag[X]
    res0: reflect.runtime.universe.TypeTag[X] = TypeTag[X]
    
    scala> .tpe
    res1: reflect.runtime.universe.Type = X
    
    scala> .members
    res2: reflect.runtime.universe.MemberScope = Scopes(constructor X, value i, method $asInstanceOf, method $isInstanceOf, method synchronized, method ##, method !=, method ==, method ne, method eq, constructor Object, method notifyAll, method notify, method clone, method getClass, method hashCode, method toString, method equals, method wait, method wait, method wait, method finalize, method asInstanceOf, method isInstanceOf, method !=, method ==)
    
    scala> res2.filter(s => s.isMethod && s.asMethod.isConstructor)
    res4: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(constructor X, constructor Object)
    
    scala> res4.iterator.next
    res7: reflect.runtime.universe.Symbol = constructor X
    
    scala> .typeSignature
    res8: reflect.runtime.universe.Type = (i: scala.Int)X
    
    scala> res7.asMethod
    res11: reflect.runtime.universe.MethodSymbol = constructor X
    
    scala> res1.typeSymbol.asClass
    res13: reflect.runtime.universe.ClassSymbol = class X
    
    scala> currentMirror reflectClass res13
    res14: reflect.runtime.universe.ClassMirror = class mirror for X (bound to null)
    
    scala> res14 reflectConstructor res11
    res16: reflect.runtime.universe.MethodMirror = constructor mirror for X.<init>(i: scala.Int): X (bound to null)
    
    scala> res16(7)
    res17: Any = X@28730c5a
    
    scala> .asInstanceOf[X]
    res18: X = X@28730c5a
    
    0 讨论(0)
  • 2020-12-24 09:55

    j3d,

    I believe the manifest approach is deprecated. You can use scala code below to create an instance via reflection. You will have to adjust the code slightly to factor for classes with multiple constructors, and/or arguments

    Code is based on http://docs.scala-lang.org/overviews/reflection/overview.html

    import scala.reflect.runtime.{universe => ru}
    import ru._
    
    ...
    
    class Person { }
    
    
    def example() = 
    {
       val instance1 = createInstance[Person]()
       val instance2 = createInstance(typeOf[Person])
    }
    
    
    def createInstance[T:TypeTag]() : Any= {
        createInstance(typeOf[T])
    }
    
    
    def createInstance(tpe:Type): Any = {
        val mirror = ru.runtimeMirror(getClass.getClassLoader)
        val clsSym = tpe.typeSymbol.asClass
        val clsMirror = mirror.reflectClass(clsSym)
        val ctorSym = tpe.decl(ru.termNames.CONSTRUCTOR).asMethod
        val ctorMirror = clsMirror.reflectConstructor(ctorSym)
        val instance = ctorMirror()
        return instance
    }
    
    0 讨论(0)
  • 2020-12-24 10:01

    Eventually here is the implementation that actually works - please just assume this answer comes from som-snytt:

    import scala.reflect.runtime._
    import scala.reflect.runtime.universe._
    
    class Test[T <: MyTrait : TypeTag] {
    
      def createInstance(args: AnyRef*)(ctor: Int = 0): T = {
        val tt = typeTag[T]
    
        currentMirror.reflectClass(tt.tpe.typeSymbol.asClass).reflectConstructor(
          tt.tpe.members.filter(m =>
            m.isMethod && m.asMethod.isConstructor
          ).iterator.toSeq(ctor).asMethod
        )(args: _*).asInstanceOf[T]
      }   
    }
    

    I hope that helps.

    0 讨论(0)
  • 2020-12-24 10:01
    object BeanFactory {
    
      import scala.reflect.runtime.universe._
      import scala.reflect.runtime.{universe => ru}
    
      def createBean[T: TypeTag](): Option[T] = {
        val typee = ru.typeOf[T]
        val constructor = typee.decl(ru.termNames.CONSTRUCTOR).asMethod
        if (constructor.isPrivate) {
          println("private class can not created ")
          None
        } else {
          val classMirror = ru.runtimeMirror(getClass.getClassLoader).reflectClass(typee.typeSymbol.asClass)
          val constructorMethod = classMirror.reflectConstructor(constructor)
          val params = constructor.paramLists.flatten.map(par => {
            if (par.typeSignature =:= typeOf[Int]) {
              0
            } else {
              if (par.typeSignature =:= typeOf[String]) {
                ""
              } else {
                if (par.typeSignature =:= typeOf[Double]) {
                  0.0
                } else {
                  if (par.typeSignature =:= typeOf[Float]) {
                    0.0f
                  } else {
                    if (par.typeSignature =:= typeOf[Char]) {
                      ""
                    } else {
                      if (par.typeSignature =:= typeOf[Boolean]) {
                        false
                      } else {
                        null
                      }
                    }
                  }
                }
              }
            }
    
          })
          Some(constructorMethod(params: _*).asInstanceOf[T])
        }
      }
    }
    

    This may end up with your problem

    0 讨论(0)
提交回复
热议问题