10

I'm trying to figure out how to instantiate a case class object with reflection. Is there any support for this? The closest I've come is looking at scala.reflect.Invocation, but this seems more for executing methods that are a part of an object.

case class MyClass(id:Long, name:String) def instantiate[T](className:String)(args:Any*) : T = { //your code here } 

Is close to the API I'm looking for.

Any help would be appreciated.

2
  • The reflection involved here has nothing to do with case classes specifically. You just need some reflection to typecast the args. If I am wrong, can you elaborate? Commented Oct 29, 2009 at 5:53
  • You are correct, except that part of the goal is to be able to write simple case classes and then use a method like this to instantiate/modify them. Commented Oct 29, 2009 at 12:39

3 Answers 3

22
scala> case class Foo(id:Long, name:String) defined class Foo scala> val constructor = classOf[Foo].getConstructors()(0) constructor: java.lang.reflect.Constructor[_] = public Foo(long,java.lang.String) scala> val args = Array[AnyRef](new java.lang.Integer(1), "Foobar") args: Array[AnyRef] = Array(1, Foobar) scala> val instance = constructor.newInstance(args:_*).asInstanceOf[Foo] instance: Foo = Foo(1,Foobar) scala> instance.id res12: Long = 1 scala> instance.name res13: String = Foobar scala> instance.getClass res14: java.lang.Class[_] = class Foo 

Currently there is not much reflection support in Scala. But you can fall back to th Java Reflection API. But there are some obstacles:

  • You have to create a Array[AnyRef] and box your "primitive types" in the wrapper classes (java.lang.Integer, java.lang.Character, java.lang.Double, ...)

  • newInstance(Object ... args) gets an varargs array of Object, so you should give the type inferer a hint with :_*

  • newInstance(...) returns an Object so you have to cast it back with asInstanceOf[T]

The closest I could get to your instantiate function is this:

def instantiate(clazz: java.lang.Class[_])(args:AnyRef*): AnyRef = { val constructor = clazz.getConstructors()(0) return constructor.newInstance(args:_*).asInstanceOf[AnyRef] } val instance = instantiate(classOf[MyClass])(new java.lang.Integer(42), "foo") println(instance) // prints: MyClass(42,foo) println(instance.getClass) // prints: class MyClass 

You cannot get the get class from a generic type. Java erases it (type erasure).

Edit: 20 September 2012

Three years on, the instantiate method can be improved to return a properly typed object.

def instantiate[T](clazz: java.lang.Class[T])(args:AnyRef*): T = { val constructor = clazz.getConstructors()(0) return constructor.newInstance(args:_*).asInstanceOf[T] } 

See http://www.nabble.com/How-do-I-get-the-class-of-a-Generic--td20873455.html

Sign up to request clarification or add additional context in comments.

2 Comments

how can we modify above program if we have input as string value of case class, i.e in above case say we have input to our program as string value of case class as "Foo".So how to construct runtime class based on string value of case class
@Aamir What about java.lang.Class.forName("Foo")?
3

See answers to Scala: How do I dynamically instantiate an object and invoke a method using reflection? as well, especially regarding type erasure.

Comments

2

This is what I've ended up with so far, I'd like to not have to deal directly with AnyRef if possible. So if anyone knows a way to get around that I'd appreciate the help.

case class MyClass(id:Long,name:String) def instantiate[T](classArgs: List[AnyRef])(implicit m : Manifest[T]) : T ={ val constructor = m.erasure.getConstructors()(0) constructor.newInstance(classArgs:_*).asInstanceOf[T] } val list = List[AnyRef](new java.lang.Long(1),"a name") val result = instantiate[MyClass](list) println(result.id) 

2 Comments

Does this really allow you to instantiate a class that you don't know about until runtime? Doesn't the type parameter to the instantiate method rule that out?
Figuring this piece out was just a small part of what I'm doing. I'm just experimenting with ideas of using immutable objects in a data access layer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.