Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: How do I dynamically instantiate an object and invoke a method using reflection?

In Scala, what's the best way to dynamically instantiate an object and invoke a method using reflection?

I would like to do Scala-equivalent of the following Java code:

Class class = Class.forName("Foo"); Object foo = class.newInstance(); Method method = class.getMethod("hello", null); method.invoke(foo, null); 

In the above code, both the class name and the method name are passed in dynamically. The above Java mechanism could probably be used for Foo and hello(), but the Scala types don't match one-to-one with that of Java. For example, a class may be declared implicitly for a singleton object. Also Scala method allows all sorts of symbols to be its name. Both are resolved by name mangling. See Interop Between Java and Scala.

Another issue seems to be the matching of parameters by resolving overloads and autoboxing, described in Reflection from Scala - Heaven and Hell.

like image 938
Eugene Yokota Avatar asked Sep 24 '09 05:09

Eugene Yokota


People also ask

What is reflection in Scala?

Scala reflection enables a form of metaprogramming which makes it possible for programs to modify themselves at compile time. This compile-time reflection is realized in the form of macros, which provide the ability to execute methods that manipulate abstract syntax trees at compile-time.

Can we create object using reflection in Java?

We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don't have the classes information at compile time, we can assign it to Object and then further use reflection to access it's fields and invoke it's methods.


2 Answers

There is an easier way to invoke method reflectively without resorting to calling Java reflection methods: use Structural Typing.

Just cast the object reference to a Structural Type which has the necessary method signature then call the method: no reflection necessary (of course, Scala is doing reflection underneath but we don't need to do it).

class Foo {   def hello(name: String): String = "Hello there, %s".format(name) }  object FooMain {    def main(args: Array[String]) {     val foo  = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }]     println(foo.hello("Walter")) // prints "Hello there, Walter"   } } 
like image 81
Walter Chang Avatar answered Sep 23 '22 04:09

Walter Chang


The answers by VonC and Walter Chang are quite good, so I'll just complement with one Scala 2.8 Experimental feature. In fact, I won't even bother to dress it up, I'll just copy the scaladoc.

object Invocation   extends AnyRef 

A more convenient syntax for reflective invocation. Example usage:

class Obj { private def foo(x: Int, y: String): Long = x + y.length } 

You can call it reflectively one of two ways:

import scala.reflect.Invocation._ (new Obj) o 'foo(5, "abc")                 // the 'o' method returns Any val x: Long = (new Obj) oo 'foo(5, "abc")  // the 'oo' method casts to expected type. 

If you call the oo method and do not give the type inferencer enough help, it will most likely infer Nothing, which will result in a ClassCastException.

Author Paul Phillips

like image 31
Daniel C. Sobral Avatar answered Sep 24 '22 04:09

Daniel C. Sobral