I know in Groovy you can invoke a method on a class/object using a string. For example:
Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1)
Is there a way to do this with the class? I have the name of the class as a string and would like to be able to dynamically invoke that class. For example, looking to do something like:
String clazz = "Foo" "$clazz".get(1)
I think I'm missing something really obvious, just am not able to figure it out.
We can invoke a static method by using its class reference. An instance method is invoked by using the object reference.
A static method in Java (also called class method) is a method that belongs to the class and not the instance. Therefore, you can invoke the method through the class instead of creating an instance first and calling the method on that instance.
Invoking a public static Method Once we hold the method object, we can invoke it simply by calling the invoke method. It's worthwhile to explain the first argument of the invoke method. If the method is an instance method, the first argument is the object from which the underlying method is invoked.
But when we try to call Non static function i.e, TestMethod() inside static function it gives an error - “An object refernce is required for non-static field, member or Property 'Program. TestMethod()”. So we need to create an instance of the class to call the non-static method.
As suggested by Guillaume Laforge on Groovy ML,
("Foo" as Class).get(i)
would give the same result.
I've tested with this code:
def name = "java.lang.Integer" def s = ("$name" as Class).parseInt("10") println s
Try this:
def cl = Class.forName("org.package.Foo") cl.get(1)
A little bit longer but should work.
If you want to create "switch"-like code for static methods, I suggest to instantiate the classes (even if they have only static methods) and save the instances in a map. You can then use
map[name].get(1)
to select one of them.
[EDIT] "$name"
is a GString
and as such a valid statement. "$name".foo()
means "call the method foo()
of the class GString
.
[EDIT2] When using a web container (like Grails), you have to specify the classloader. There are two options:
Class.forName("com.acme.MyClass", true, Thread.currentThread().contextClassLoader)
or
Class.forName("com.acme.MyClass", true, getClass().classLoader)
The first option will work only in a web context, the second approach also works for unit tests. It depends on the fact that you can usually use the same classloader as the class which invokes forName()
.
If you have problems, then use the first option and set the contextClassLoader
in your unit test:
def orig = Thread.currentThread().contextClassLoader try { Thread.currentThread().contextClassLoader = getClass().classLoader ... test ... } finally { Thread.currentThread().contextClassLoader = orig }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With