Miguel Pardal
Miguel Pardal

Reputation: 599

Groovy way to dynamically instantiate a class from String

The answers of this question about the Groovy way to dynamically invoke a static method were very helpful but I'm having trouble with the following case:

I defined a simple Groovy class:

class Item {
  def id = 1
  def data = [ "a", "b" ]
}

I then defined a simple utility class that wants to dynamically load the Item class:

class Util {
  static def main(args) {
     def cls = "Item" as Class
     def instance = cls.newInstance()
     println instance.toString()
  }
}

Util.groovy is in the same folder as Item.groovy

When I try to run Util.groovy I get the following error:

Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: 
Cannot cast object 'Item' with class 'java.lang.String' 
to class 'java.lang.Class' due to: 
java.lang.ClassNotFoundException: Item
        at Util.main(Util.groovy:3)

The only way that I could make it work was by using groovyc to precompile Item.groovy, but this misses the point of being Groovy :)

Upvotes: 27

Views: 26744

Answers (3)

Pablo Pazos
Pablo Pazos

Reputation: 3216

Another option using Class.forName() from Java (https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Class.html#forName(java.lang.String))

Example working code in Groovy:

class Dog {

   def bark()
   {
      println 'woof'
   }
}


def name = 'Dog'

def ins = Class.forName(name).newInstance()

ins.bark() // woof

Upvotes: 0

tim_yates
tim_yates

Reputation: 171154

This works, using the underlying GroovyClassLoader:

def instance = this.class.classLoader.loadClass( 'Item', true, false )?.newInstance()

Upvotes: 39

Bill K
Bill K

Reputation: 62789

I just had to do this and found an interesting way--so I thought I'd come back and mention it.

I had A problem with this because I wanted to pass a value to newInstance (use a non-default constructor) and all the solutions seemed to be a little bit of work (I'm lazy, okay?)

Anyway, suppose you want to create a new Integer(5)... try this:

c = "java.lang.Integer"
p = "5"
def result = Eval.me("return new ${c}(${p})")
assert(result == 5)

Worked really well although I'm sure it's about the slowest solution possible. Has the advantage that the method is applicable to many other situations.

Upvotes: 7

Related Questions