Groovy Subclassing Hiccup

“Could not find matching constructor” instantiating inner Java class from Groovy

I’m not sure if this is a bug or not.  Seems like it to me.  But there’s an easy work-around once you know what you’re dealing with.

Let’s say you have some legacy Java code you’re working with, and you’re working in Groovy. That makes you happy, right? So, let’s say the Java class, Earth, has an inner class, Fire. We’ll say Fire has a constructor that takes a parameter.

// c m semicolons? m r javas
package issues.subclassedhiccup;
public class Earth
{
  public class Fire
  {
    public Fire (int inWhoosh)
    {
      whoosh = inWhoosh;
    }
    public long doubleWhoosh ()
    {
      whoosh *= whoosh;
      return whoosh;
    }
    long whoosh;
  }
}

Great, so you need to extend the Earth thingy in your code, you know, to make it better. No problem, go ahead. Then in your subclassed code you try to instantiate a new Fire. Maybe something like this:

// groovy!
package issues.subclassedhiccup
class Water
{
  class Air
    extends Earth
  {
    Fire createFire (int whoosh)
    {
      return new Fire(whoosh)
    }
  }
  long doBigWhoosh (int base, int times)
  {
    def air = new Air()
    def fire = air.createFire(base)
    def value = 0
    for (i in 0..times)
    { value = fire.doubleWhoosh() }
    return value
  }
  static public main (String[] args)
  {
    System.out << "2 raised 3 times is ${new Water().doBigWhoosh(2,3)}"
  }
}

Awesome! Good work. Now run it, and behold!

Exception in thread “main” groovy.lang.GroovyRuntimeException: Could not find matching constructor for: issues.subclassedhiccup.Earth$Fire(java.lang.Integer)

How odd.  It can’t find Fire, even though it’s defined in our base class.  Hrm.  Well, explicitly qualifying that guy fixes this issue.  Just change the createFire method like so:

    Earth.Fire createFire (int whoosh)
    {
      return new Earth.Fire(whoosh)
    }

Run it, and behold!

Exception in thread “main” groovy.lang.GroovyRuntimeException: Could not find matching constructor for: issues.subclassedhiccup.Earth$Fire(java.lang.Integer)

Holy quacomole! What is this madness?

After a few hours of rather creative cursing and thoroughly depilating head scratching my conclusion is, it’s broke. The constructors of inner classes always have an implied parameter of the outter class’s this. Well, unless it’s a static inner class. In this case, it seems Groovy is trying to find a constructor with the implied guy that matches the extended class rather than allowing for one that matches the base class. Not finding one, it just horks.

In other words, I think it’s looking for a constructor of Fire defined as:

  public Fire (Air parent, int inWhoosh)

And not looking at the superclasses of Air, in this case:

  public Fire (Earth parent, int inWhoosh)

Fortunately there’s a simple work-around. Just manually inject the this. So the createFire method becomes:

    Earth.Fire createFire (int whoosh)
    {
      return new Earth.Fire(this,whoosh)
    }

Run it, and behold!

2 raised 3 times is 65536

Great. Fixed. So, we encountered two issues in here:

1) The inner class had to be qualified in the subclass: Earth.Fire

2) The instantiation of the inner class from the subclass had to have an additional this parameter added as the first parameter: new Earth.Fire(this,whoosh)

Leave a Reply