Why does an anonymous class constructed throw an error given named parameters in Groovy?

Viewed 70

I'm studying Groovy at the moment, and I have a question related to unexpected behavior when using anonymous classes.

So, I've learned that Groovy autogenerates smart constructors that can destructure the provided hashmap and set the given values to the corresponding properties:

class Greeter {
  String name
}

def alice = new Greeter(name: "Alice")
println "Hello, $alice.name" // "Hello, Alice"

Also, I've learned that it is possible to create derived classes anonymously like shown below:

def bob = new Greeter() {
  def greet() {
    println "Hello, $name"
  }
}

bob.name = "Bob"
bob.greet() // "Hello, Bob"

However, what I can't comprehend is what exactly is wrong with this scenario:

def chuck = new Greeter(name: "Chuck") {
  def greet() {
    println "Hello, $name"
  }
}

chuck.greet(); /*
Caught: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: Greeter(LinkedHashMap)
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: Greeter(LinkedHashMap)
    at anonymous-class$2.<init>(anonymous-class.groovy)
    at anonymous-class.run(anonymous-class.groovy:17)
*/

So, here I basically combine the first and the second feature, and something breaks behind the curtains. Is that a known behavior or a bug?

Thanks in advance!

1 Answers

When you call new Greeter(name: "Alice"), it is first creating a new Greeter object using the default (zero argument) constructor, then assigning the property. You can actually generate the map inputs constructor using the @Canonical annotation:

@Canonical
class Greeter {
    String name
}

Now when you use the syntax from the question, it will work as expected, because you are calling an actual constructor.

Related