how do I override JUST the constructor in a Groovy class? - groovy

I would like to override ONLY the behavior of the constructor in a groovy class. Like so
class Foo {
def a
def b
Foo(int a, int b) {
this.a = a
this.b = b
println("I'm a Foo!")
}
}
class Bar extends Foo {
Bar(int a, int b) {
this.a = 2*a
this.b = 2*b
println("I'm a Bar!")
}
}
def f = new Foo(1, 2)
def b = new Bar(1, 2)
when I run this, the def f = new Foo(1, 2) line run successfully, but def bar = new Bar(1, 2) throws an exception:
I'm a Foo!
Caught: java.lang.NoSuchMethodError: Foo: method <init>()V not found
java.lang.NoSuchMethodError: Foo: method <init>()V not found
So I'm confused here. How do I override ONLY the constructor of a class property.
(incidentally, IntelliJ is complaining about the definition of the Bar constructor, saying 'There is no default constructor available in class Foo'), and that is confusing to me as well.
UPDATE:
I found that I could solve the problem by adding a no-arg constructor to Foo as Foo() {}. And that seems to solve the problem with Bar. But I still have no idea what's going on here.

groovy based on java and in java you can't override constructor of ancestor. you can only extend it.
if you are not specifying which constructor to extend by using super(a, b) (for example) - then compiler will try to use default parent constructor super() - and here you got an original error.
java.lang.NoSuchMethodError: Foo: method ()V not found
so, this one should work:
class Foo {
def a
def b
String toString(){ "${this.getClass()}[$a, $b]" }
Foo(int a, int b) {
this.a = a
this.b = b
println("I'm a Foo!")
}
}
class Bar extends Foo {
Bar(int a, int b) {
super(a, b) // <<-- the only change
this.a = 2*a
this.b = 2*b
println("I'm a Bar!")
}
}
def f = new Foo(1, 2)
def b = new Bar(1, 2)
println f
println b
result:
I'm a Foo!
I'm a Foo! <<-- this is coming from Bar (inherited from Foo)
I'm a Bar!
class Foo[1, 2]
class Bar[2, 4]

Related

MissingMethodException when calling method inside another

I am trying to call a method inside another and I am getting a MissingMethodException. My code looks something like this:
class Foo {
static def bar {
//do stuff
return something
}
static def baz { myVar=false ->
def something = bar()
//do stuff w/something
}
}
Foo.baz()
and this is the error I get: Caught: groovy.lang.MissingMethodException: No signature of method: Foo$__clinit__closure6.bar() is applicable for argument types: () values: []
I found that I can fix this error if I define baz like this instead:
static def baz { myVar=false ->
def something = this.bar()
//do stuff w/something
}
but if I do that, my IDE tells me that this is an Unnecessary qualified reference.
What's going on here?
That syntax in your snippet is wrong. Either you wanted static def bar = {} or static def bar() {}.
If you wanted bar to be a method, then there is no error:
class Foo {
static bar() { 'something' }
static baz = { myVar=false ->
def something = bar()
return something + "!"
}
}
assert Foo.baz() == "something!"
If you want bar to be a closure (i.e. bar = {}) then to invoke bar from baz you need to put the class name first:
class Foo {
static bar = { 'something' }
static baz = { myVar=false ->
def something = Foo.bar()
return something + "!"
}
}
assert Foo.baz() == "something!"

Add parameterized method to groovy class?

In groovy I can add a method to a class:
g.metaClass.bye = { println "Goodbye, $name" }
g.bye()
How can I add a method with parameters. Something like bye(int a, int b)?
Just add parameters to your closure
g.metaClass.bye = { int a, int b ->
a + b
}

Coercion befuddlement in Groovy

Why does the following
class Test {
#Test
void go() {
def foo1 = new MockFoo1() as Foo
def foo2 = new MockFoo2() as Foo
}
interface Foo {}
class MockFoo1 {}
class MockFoo2 {}
}
Result in a java.lang.IllegalArgumentException: argument type mismatch on the foo2 coercion?
This only happens if I coerce 2 objects of 2 different types to the same interface during a single path of execution. The groovy approved way of using closures or maps to achieve this kind of duck typing works fine.
Any light shed appreciated.
It's a bug with the ProxyGenerator adapterCache. As a workaround, you can also use some Groovy trickery to make this work:
interface Foo {
static a = {
[MockFoo1, MockFoo2].each {
it.metaClass.asType = { Class klazz ->
try {
DefaultGroovyMethods.asType(delegate, klazz)
} catch (e) {
def cache = ProxyGenerator.INSTANCE.#adapterCache.#cache
cache.each { k, v ->
cache.remove(k)
}
DefaultGroovyMethods.asType(delegate, klazz)
}
}
}
}()
}
class MockFoo1 {}
class MockFoo2 {}
def a = new MockFoo1() as Foo
def b = new MockFoo2() as Foo
assert a instanceof Foo
assert b instanceof Foo
Hope this helps!

Unexpected behavior with overloaded methods

I'm a bit confused about groovys method overloading behavior: Given the class
and tests below, I am pretty okay with testAStringNull and testBStringNull
throwing ambiguous method call exceptions, but why is that not the case for
testANull and testBNull then?
And, much more importantly: why does testBNull(null)
call String foo(A arg)? I guess the object doesn't know about the type of the variable it's bound to, but why is that call not ambiguous to groovy while the others are?
(I hope I explained well enough, my head hurts from generating this minimal
example.)
class Foo {
static class A {}
static class B {}
String foo(A arg) { return 'a' }
String foo(String s, A a) { return 'a' }
String foo(B arg) { return 'b' }
String foo(String s, B b) { return 'b' }
}
Tests:
import org.junit.Test
import Foo.A
import Foo.B
class FooTest {
Foo foo = new Foo()
#Test
void testA() {
A a = new A()
assert foo.foo(a) == 'a'
}
#Test
void testAString() {
A a = new A()
assert foo.foo('foo', a) == 'a'
}
#Test()
void testANull() {
A a = null
assert foo.foo(a) == 'a'
}
#Test
void testAStringNull() {
A a = null
assert foo.foo('foo', a) == 'a'
}
#Test
void testB() {
B b = new B()
assert foo.foo(b) == 'b'
}
#Test
void testBString() {
B b = new B()
assert foo.foo('foo', b) == 'b'
}
#Test
void testBNull() {
B b = null
assert foo.foo(b) == 'b'
}
#Test
void testBStringNull() {
B b = null
assert foo.foo('foo', b) == 'b'
}
}
It's a (somewhat little-known) oddity of Groovy's multi-dispatch mechanism, which as attempting to invoke the "most appropriate" method, in combination with the fact that the provided static type (in your case A or B) is not used as part of the dispatch mechanism. When you declare A a = null, what you get is not a null reference of type A, but a reference to NullObject.
Ultimately, to safely handle possibly null parameters to overloaded methods, the caller must cast the argument, as in
A a = null
assert foo.foo('foo', a as A) == 'a'
This discussion on "Groovy Isn't A Superset of Java" may shed some light on the issue.

How to select specific field using Groovy Closure

Given:
class FruitBasket {
int apples = 0
int oranges = 0
}
I need to pick out apples from each FruitBasket. The work need to be done in processFruit:
def processFruit(list, picker) {
list.each {
println "processing " + picker(it)
}
}
def processAll() {
List fruitList = [
new FruitBasket("apples": 2, "oranges": 4),
new FruitBasket("apples": 3, "oranges": 5)
]
processFruit(fruitList, applePicker)
}
def applePicker(FruitBasket f) {
return f.getApples()
}
but it is complaining # runtime that
No such property: applePicker for class: FooTest
possibly a problem with the closures FruitBasket arg...
In that code, applePicker is a method, not a closure.
You can either use a method handle to pass the method as a parameter like so:
processFruit(fruitList, this.&applePicker)
Or change it to an actual closure:
def applePicker = { FruitBasket f -> return f.getApples()    }
You are passing applePicker to processFruit, but it is a method. You can only pass closures this way. Redefine applePicker as a closure like so:
applePicker = { FruitBasket f ->
return f.getApples()
}
Or convert the method to a closure when processFruit is called:
processFruit(fruitList, this.&applePicker)

Resources