I know there are similar questions but the answers are not satisfying.
I get an Groovy ambiguous method overload error when calling a method with null as parameter.
e.g.:
class A{
sampleMethod (B bObj){
if(bObj == null) {
handleNullArgumentGracefully()
}
... do some cool stuff ...
}
sampleMethod (C cObj){
... do some other cool stuff ...
}
}
now when i call sampleMethod(null) groovy does not know which method it should invoke. Thats clear but is there a possibility to set one method of these two as default method to handle such null calls? I want to handle this on the callee side and not on the caller side (i do not want to cast something on the caller side)
UPDATE:
i found a solution how it could work but i donĀ“t know why: convert the non default method to a closure property
class app {
static void main(String[] args) {
def a = new A()
a.sampleMethod(new B())
a.sampleMethod(new C())
a.sampleMethod(null)
}
}
class A {
def sampleMethod(B bObj = null) {
if (bObj == null) {
println("handle null")
}
println("1")
}
def sampleMethod = { C cObj ->
println("2")
}
}
class B {
}
class C {
}
the following will fail with Ambiguous method overloading for method A#sampleMethod
class A{
def sampleMethod (Number o=null){
println "num $o"
}
def sampleMethod (String o){
println "str $o"
}
}
new A().sampleMethod(null)
this one will work (Object will be called for null):
class A{
def sampleMethod (Number o=null){
println "num $o"
}
def sampleMethod (String o){
println "str $o"
}
def sampleMethod(Object o){
println "obj $o"
}
}
new A().sampleMethod(null)
but i like this one:
class A{
def _sampleMethod (Number o){
println "num $o"
}
def _sampleMethod (String o){
println "str $o"
}
def sampleMethod(Object o){
if(o==null){
println "null"
return null
}else if(o instanceof Number){
return _sampleMethod ((Number) o)
}else if(o instanceof String){
return _sampleMethod ((String) o)
}
throw new IllegalArgumentException("wrong argument type: ${o.getClass()}")
}
}
new A().sampleMethod(null)
Related
My test code below:
#!/usr/bin/env groovy
class Inner {
def methodMissing(String name, args) {
println "inner:${name}"
}
}
def foo = {
bar()
}
foo.delegate = new Inner()
foo.call()
It gives result:
inner:bar
If I add another methodMissing method, like this:
#!/usr/bin/env groovy
class Inner {
def methodMissing(String name, args) {
println "inner:${name}"
}
}
// This method is added
def methodMissing(String name, args) {
println "outer:${name}"
}
def foo = {
bar()
}
foo.delegate = new Inner()
foo.call()
It gives result:
outer:bar
Why? I set the delegate to the closure 'foo'. Why isn't Inner. methodMissing called?
From this doc, I believe you'll want to change the resolution strategy. I have added a foo2 and some asserts to illustrate the contrast in behaviour:
class Inner {
def methodMissing(String name, args) {
println "inner:${name}"
return "inner:${name}"
}
}
def methodMissing(String name, args) {
println "outer:${name}"
return "outer:${name}"
}
def foo = { bar() }
foo.delegate = new Inner()
assert "outer:bar" == foo.call()
def foo2 = { bar() }
foo2.delegate = new Inner()
foo2.resolveStrategy = Closure.DELEGATE_FIRST
assert "inner:bar" == foo2.call()
I'm trying to figure out something for my own project so I made this example to better explain it. Class Thing has a delegate Type called overrides. Methods in overrides should be called when:
The method is declared in overrides
The method is declared in overrides but not in `this
Methods in this should be called when:
the method is not declared in overrides
the method is inherited from Object, GroovyObject
the method is missing (missingMethod)
I have considered using #Delegate but I need to change overrides at runtime. Here is the code.
class Thing implements GroovyInterceptable {
Type overrides = new BigThing()
Object invokeMethod(String name, Object args) {
MetaMethod thingMethod = metaClass.getMetaMethod('findDeclaredMethod', [this, name, args] as Object[])
.invoke(this, name, args)
MetaMethod overrideMethod = findDeclaredMethod(overrides, name, args)
if(overrideMethod) {
overrideMethod.invoke(overrides, args)
//maybe invoke missingMethod on overrides catch MissingMethodException and call thingMethod
} else if(thingMethod) {
thingMethod.invoke(this, args)
} else {
this.metaClass.invokeMissingMethod(this, name, args)
}
}
MetaMethod findDeclaredMethod(Object obj, String name, Object args) {
MetaMethod m = this.metaClass.getMetaMethod(name, args)
if(m && m.declaringClass.theClass != Thing.getClass()) {
m = null
}
return m
}
String method1() {
return "from Thing method1() ${makeString()}"
}
String method2() {
return "from Thing method2() ${makeString()}"
}
}
interface Type {
String makeString()
}
class BigThing implements Type {
String makeString() {
return "makeString()"
}
String method2() {
return "from BigThing method2() ${makeString()}"
}
}
assert 'from Thing method1() makeString()' == new Thing().method1()
assert 'from BigThing method2() makeString()' == new Thing().method2()
new Thing().with {
assert 'from Thing method1() makeString()' == method1()
assert 'from BigThing method2() makeString()' == method2()
}
Note: this currently doesn't work but I think it explains the idea well enough.
Is there an already established pattern for something like this in groovy?
Update:
With this I am part way there. It fails on calling method2() in a with closure.
class Thing implements GroovyInterceptable {
Type overrides = new BigThing()
Object invokeMethod(String name, Object args) {
MetaMethod method = overrides.metaClass.getMetaMethod(name, args)
if(method != null) {
System.out.println("$method.name class is $method.declaringClass.theClass")
System.out.println("$method.declaringClass.theClass interfaces contains Type or is type ${method.declaringClass.theClass == Type || method.declaringClass.theClass.interfaces.contains(Type)}")
}
if (method != null && (method.declaringClass.theClass == Type || method.declaringClass.theClass.interfaces.contains(Type))) {
return method.invoke(overrides, args)
}
method = this.metaClass.getMetaMethod(name, args)
if (method != null) {
return method.invoke(this, args)
}
return this.metaClass.invokeMissingMethod(this, name, args)
}
String method1() {
return "from Thing method1() ${makeString()}"
}
String method2() {
return "from Thing method2() ${makeString()}"
}
}
interface Type {
String makeString()
}
class BigThing implements Type {
String makeString() {
return "makeString()"
}
String method2() {
return "from BigThing method2() ${makeString()}"
}
}
assert 'from Thing method1() makeString()' == new Thing().method1()
assert 'from BigThing method2() makeString()' == new Thing().method2()
new Thing().with {
assert 'from Thing method1() makeString()' == method1()
assert 'from BigThing method2() makeString()' == method2()
}
Try simplifying GroovyObject.invokeMethod(String name, Object args) method implementation. You could achieve this by implementing that method in following way:
firstly check if overrides has method with that name and invoke it if it does exist
check if current object has method with that name and invoke it
invoke invokeMissingMethod otherwise
I have checked following implementation and it worked fine:
class Thing implements GroovyInterceptable {
Type overrides = new BigThing()
Object invokeMethod(String name, Object args) {
MetaMethod method = overrides.metaClass.getMetaMethod(name, args)
if (method != null) {
return method.invoke(overrides, args)
}
method = this.metaClass.getMetaMethod(name, args)
if (method != null) {
return method.invoke(this, args)
}
return this.metaClass.invokeMissingMethod(this, name, args)
}
String method1() {
return "from Thing method1() ${makeString()}"
}
String method2() {
return "from Thing method2() ${makeString()}"
}
}
interface Type {
String makeString()
}
class BigThing implements Type {
String makeString() {
return "makeString()"
}
String method2() {
return "from BigThing method2() ${makeString()}"
}
}
assert 'from Thing method1() makeString()' == new Thing().method1()
assert 'from BigThing method2() makeString()' == new Thing().method2()
I hope it helps.
At the moment I have the following code:
class SampleFixture {
static aFixtureWithCodeAA() {
fixtureAA()
}
static aFixtureWithCodeBB() {
fixtureBB()
}
static aFixtureWithCodeCC() {
fixtureCC()
}
}
I'd like to transform this into something like
class SampleFixture {
static aFixture(code) {
fixture[code]()
}
}
I have another class where fixtureAA, fixtureBB and fixtureCC are defined. So the code values are predefined. I want the method fixture[code] to be build at run-time rather than having a method for every single fixture.
How can I do this?
EDIT: I've been reading this http://groovy-lang.org/metaprogramming.html#_dynamic_method_names and it looks like what I want to do but I can't seem to get it to work.
Just to clarify: after reading this article, what I would like to end up with is a method with a baseName+varSufix as in "fixture${code}"(). Ideally I would end up with something like:
class SampleFixture {
static aFixture(code) {
MyClass."fixture{code}"()
}
}
So I'd have a different method name depending on the code I am passing.
Do you just mean:
class MyClass {
static fixtureAA() { "oooh, aa" }
static fixtureBB() { "cool, bb" }
static fixtureCC() { "wow, cc" }
}
class MyFixture {
def call(code) {
MyClass."fixture$code"()
}
}
println new MyFixture().call('BB')
(you were so close)
Or, you could do something like:
class MyClass {
static fixtureAA() { "oooh, aa" }
static fixtureBB() { "cool, bb" }
static fixtureCC() { "wow, cc" }
}
class MyFixture {
def methodMissing(String name, args) {
try {
MyClass."fixture$name"()
}
catch(e) {
"No idea how to $name"
}
}
}
assert "oooh, aa" == new MyFixture().AA()
assert "cool, bb" == new MyFixture().BB()
assert "wow, cc" == new MyFixture().CC()
assert "No idea how to DD" == new MyFixture().DD()
You can implement a method called invokeMethod(String method, args) and parse the code from the method argument:
class SampleFixture {
def fixture = [
AA: { "code aa" },
BB: { "code bb" },
CC: { "code cc" },
]
def invokeMethod(String method, args) {
def code = method - "aFixtureWithCode"
fixture[code]()
}
}
f = new SampleFixture()
assert f.aFixtureWithCodeAA() == "code aa"
assert f.aFixtureWithCodeBB() == "code bb"
assert f.aFixtureWithCodeCC() == "code cc"
UPDATE: here's a solution using a second class to redirect the method call to another class
class Fixture {
def fixtureAA() { "code aa" }
def fixtureBB() { "code bb" }
def fixtureCC() { "code cc" }
}
class SampleFixture {}
SampleFixture.metaClass.static.invokeMethod = { String method, args ->
def code = method - "aFixtureWithCode"
new Fixture()."fixture${code}"()
}
assert SampleFixture.aFixtureWithCodeAA() == "code aa"
assert SampleFixture.aFixtureWithCodeBB() == "code bb"
assert SampleFixture.aFixtureWithCodeCC() == "code cc"
I would like to apply a meta-programming transformation to some of my classes, let's say by adding printXxx methods, like this:
class Person {
String name
}
def p = new Person()
p.printName() // does something
I have a rough idea how this can be done once I have a metaclass:
Person.metaClass.methodMissing = { name, args ->
delegate.metaClass."$name" = { println delegate."${getPropName(name)}" }
delegate."$name"(*args)
}
Now how do I turn this code into a reusable "library"? I would like to do something like:
#HasMagicPrinterMethod
class Person {
String name
}
or
class Person {
String name
static {
addMagicPrinters()
}
}
Define the behaviour you want to add as a trait
trait MagicPrinter {
void printProperties() {
this.properties.each { key, val ->
println "$key = $val"
}
}
}
Then add this trait to a class
class Person implements MagicPrinter {
String name
}
Now use it!
new Person(name: 'bob').printProperties()
You can go for a mixin approach:
class AutoPrint {
static def methodMissing(obj, String method, args) {
if (method.startsWith("print")) {
def property = (method - "print").with {
it[0].toLowerCase() + it[1..-1]
}
"${obj.getClass().simpleName} ${obj[property]}"
}
else {
throw new NoSuchMethodException()
}
}
}
You can mix it with a static block:
class Person {
static { Person.metaClass.mixin AutoPrint }
String name
}
def p = new Person(name: "john doe")
try {
p.captain()
assert false, "should've failed"
} catch (e) {
assert true
}
assert p.printName() == "Person john doe"
Or with expandoMetaClass:
class Car {
String model
}
Car.metaClass.mixin AutoPrint
assert new Car(model: "GT").printModel() == "Car GT"
Because 7 months later is the new 'now' :-)
Is there a way to replace using the metaclass object, a method that is of a super class.
Example:
class A {
def doIt(){
two()
println 'do it!'
}
protected two(){
println 'two'
}
}
class B extends A{
def doLast(){
doIt()
}
}
B b = new B();
b.doIt()
/*
* two
* doit!
*/
b.metaClass.two = {
println 'my new two!'
}
b.doIt();
/*
* my new two!
* do it!
*/
Since two and doIt are declared in the same class, groovy will skip the meta-object protocol for this call. You can override this behavior by marking the super class as GroovyInterceptable, which forces all method calls to go through invokeMethod. For example:
class A implements GroovyInterceptable {
def doIt(){
two()
println 'do it!'
}
protected two(){
println 'two'
}
}
class B extends A {
def doLast(){
doIt()
}
}
B b = new B()
b.doIt() // prints two
b.metaClass.two = {
println 'my new two!'
}
b.doIt() // prints my new two!