26

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 :)

Community
  • 1
  • 1
Miguel Pardal
  • 579
  • 1
  • 8
  • 19

2 Answers2

38

This works, using the underlying GroovyClassLoader:

def instance = this.class.classLoader.loadClass( 'Item', true, false )?.newInstance()
khagler
  • 3,996
  • 29
  • 40
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • 1
    You should probably change `this.class` to `this.getClass()`. It's generally recommended to use the full method to avoid [property or map lookups (or invokeMethod overrides)](http://groovy.329449.n5.nabble.com/class-vs-getClass-td368617.html). – OverZealous Oct 13 '11 at 22:52
  • 9
    Why bother when we know this isn't a map? Embrace the dynamic! ;-) – tim_yates Oct 14 '11 at 05:29
  • 5
    You can also supply constructor arguments straight into newInstance() in 3 different forms: map, array, or comma list – Daniel Jan 06 '17 at 00:13
7

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.

GreenGiant
  • 4,930
  • 1
  • 46
  • 76
Bill K
  • 62,186
  • 18
  • 105
  • 157