How to instantiate a type T at runtime using TypeTags

The following describes how to create a new instance of type T at run time using Manifest :

 trait MyTrait class MyClass1(val name: String) extends MyTrait class MyClass2(val name: String) extends MyTrait class Test[T <: MyTrait] { def createInstance[T](name: String)(implicit m: Manifest[T]): T = { m.runtimeClass.getConstructors()(0) .newInstance(name).asInstanceOf[T] } def doSomething() { val myClass = createInstance("joe") ... } } ... val test = new Test[MyClass1] test.doSomething 

The createInstance method createInstance creates a new instance of one of the classes that implements MyTrait and calls the constructor with the given line. How to implement the same with TypeTag ?


Reimplemented with scala.reflect.runtime._

The following is the Test class, overridden as suggested by som-snytt:

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

While I call createInstance on Test , it works:

 val test = new Test[MyClass1] val myClass = test.createInstance("hello") // this works 

But as soon as I define a new class derived from Test ...

 class DerivedTest[T <: MyTrait] extends Test[T] 

... and I call createInstance in this new class, like this ...

 val test = new DerivedText[MyClass1] val myClass = test.createInstance("hello") // this crashes 

... I get the following error:

 java.util.NoSuchElementException: next on empty iterator at scala.collection.Iterator$$anon$2.next(Iterator.scala:39) at scala.collection.Iterator$$anon$2.next(Iterator.scala:37) at scala.collection.LinearSeqLike$$anon$1.next(LinearSeqLike.scala:62) at DerivedTest$class.createInstance(<console>:27) at $anon$1.createInstance(<console>:26) at .<init>(<console>:28) at .<clinit>(<console>) at .<init>(<console>:7) at .<clinit>(<console>) at $print(<console>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) ... 

Did I miss something?

+8
reflection scala
source share
3 answers

Ultimately, here is an implementation that really works - 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 this helps.

+5
source share

Maybe someone who does this all the time may call back, but it took me a lot of steps to reproduce it.

I run REPL -i, so autocomplete breaks. This 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 
+4
source share

J3D,

I believe the manifest approach is out of date. You can use the scala code below to create an instance through reflection. You will have to modify the code a bit to factor for classes with multiple constructors and / or arguments

Code 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 } 
+2
source share

All Articles