replacing toString using Groovy metaprogramming - groovy

In the following Groovy snippet, I attempt to replace both the hashCode and toString methods
String.metaClass.toString = {-> "override" }
String.metaClass.hashCode = {-> 22 }
But when I test it out, only the replacement of hashCode works
String s = "foo"
println s.hashCode() // prints 22
println s.toString() // prints "foo"
Is toString somehow a special case (possibly for security reasons)?

See the first comment on this issue. It says about String's toString and other String related classes:
(...) seems to be intent, it is probably a
good idea to have a faster invocation
for classes that don't allow
overriding toString().

This is a know defect.
Basically Groovy does not correctly override methods that are part of an interface implementation.
This works:
class T {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
assert !t.doIt()
This doesn't:
interface I {
def doIt()
}
class T implements I {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
assert !t.doIt()
Because toString() in String comes from CharSequence the correct way to override would be:
CharSequence.metaClass.toString = {-> "silly"}
println "hello world".toString()

Related

Groovy: add a method to a closure

I have the following closure
def closure = {
println ("closure code")
}
And i would like to add a method to it.
but if I try
closure.metaClass.fun = { c->
c.call();
println ("extra code");
}
I get an Exception
groovy.lang.MissingPropertyException: No such property: fun for class: org.codehaus.groovy.runtime.metaclass.ClosureMetaClass
Reading another answer, i also blindly tried to call
ExpandoMetaClass.enableGlobally()
but it's not working.
Is there a way to achive what I want?
You can do:
def closure = {
println "closure code"
}
closure.getMetaClass().fun = { ->
delegate.call()
println "extra code"
}
closure.fun()
Which prints:
closure code
extra code
Another simpler approach could be:
def closure = {
println "closure code"
}
closure.fun = { ->
closure()
println "extra code"
}
closure.fun()
The downside of this approach is that I'm referencing the closure variable directly though, instead of going through the delegate.

How do I intercept calls in Groovy?

I have this class structure:
interface bug
{
def method()
}
public class A implements bug{
def method()
{
println "Works"
}
}
A varaiable = new A()
bug.metaClass.invokeMethod {
name,args ->
println "Came here"
}
varaiable.method()
when I do this, I get Works. Why not Came here?
Where I'm doing the mistake?
EDIT:
Even if I do:
A.metaClass.invokeMethod {
name,args ->
println "Came here"
}
I'm getting only Works.
​
You're changing the metaClass of A with
A.metaClass.invokeMethod { name,args ->
println "Came here"
}
After you construct the variable. If you put this block before the line
A varaiable = new A()
It should work as you'd expect.
To get round this, you can use:
ExpandoMetaClass.enableGlobally()
And instances will check back with the metaClass every invocation, however as expected this can slow things down

Groovy runtime method interception

I'm playing with Groovy and I wonder, why doesn't this piece of code works?
package test
interface A {
void myMethod()
}
class B implements A {
void myMethod() {
println "No catch"
}
}
B.metaClass.myMethod = {
println "Catch!"
}
(new B()).myMethod()
It prints out No catch, while I expect it to print Catch! instead.
It's a bug in Groovy, there is an open issue in JIRA: Cannot override methods via metaclass that are part of an interface implementation, GROOVY-3493.
Instead of rewriting B.metaClass.myMethod, try following:
B.metaClass.invokeMethod = {String methodName, args ->
println "Catch!"
}
This blog post describes it quite well.
There is a workaround but it only applies to all classes and not specific instances.
metaclass modification BEFORE construction:
interface I {
def doIt()
}
class T implements I {
def doIt() { true }
}
I.metaClass.doIt = { -> false }
T t = new T()
assert !t.doIt()
metaclass modification AFTER construction:
interface I {
def doIt()
}
class T implements I {
def doIt() { true }
}
T t = new T()
// Removing either of the following two lines breaks this
I.metaClass.doIt = { -> false }
t.metaClass.doIt = { -> false }
assert !t.doIt()

Groovy AST Transformations - How can I figure out the return type of a MethodCallExpression?

With Groovy AST Transformations, how can I figure out the return type of a MethodCallExpression?
MethodCallExpression.getType() always returns java.lang.Object even if I explicitly define the return type of the method in the method definition.
Due to the dynamic nature of groovy, the AST can't know the return type of a method call expression at compile time. For example:
class Example {
String foo() { "foo" }
}
def e = new Example()
assert e.foo() == "foo"
Looks simple enough. foo returns a string, so the MethodCallExpression for e.foo() should have a type of String, right? But what if foo is changed in the metaClass?
class Example {
String foo() { "foo" }
}
def e = new Example()
if (someRuntimeCondition) {
e.metaClass.foo = { -> 42 }
}
assert e.foo() == "foo" // is foo a String or an Int?
The groovy compiler just doesn't have enough information to make any assumptions about the method call since it could change at runtime, so it has to compile it down to an Object.

In groovy, is there a way to check if an object has a given method?

Assuming that I have an object someObj of indeterminate type, I'd like to do something like:
def value = someObj.someMethod()
Where there's no guarantee that 'someObj' implements the someMethod() method, and if it doesn't, just return null.
Is there anything like that in Groovy, or do I need to wrap that in an if-statement with an instanceof check?
Use respondsTo
class Foo {
String prop
def bar() { "bar" }
def bar(String name) { "bar $name" }
}
def f = new Foo()
// Does f have a no-arg bar method
if (f.metaClass.respondsTo(f, "bar")) {
// do stuff
}
// Does f have a bar method that takes a String param
if (f.metaClass.respondsTo(f, "bar", String)) {
// do stuff
}
Just implement methodMissing in your class:
class Foo {
def methodMissing(String name, args) { return null; }
}
And then, every time you try to invoke a method that doesn't exist, you will get a null value.
def foo = new Foo();
assert foo.someMethod(), null
For more information, take a look here: http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing
You should be able to do something like:
SomeObj.metaClass.getMetaMethod("someMethod")
Or you can fall back to the good old Java reflection API.
You can achieve this by using getMetaMethod together with the safe navigation operator ?.:
def str = "foo"
def num = 42
def methodName = "length"
def args = [] as Object[]
assert 3 == str.metaClass.getMetaMethod(methodName, args)?.invoke(str, args);
assert null == num.metaClass.getMetaMethod(methodName, args)?.invoke(num, args);
if class :
MyClass.metaClass.methods*.name.any{it=='myMethod'}//true if exist
if object :
myObj.class.metaClass.methods*.name.any{it=='myMethod'}//true if exist
In very concise way you can use this:
if(someObj.&methodName){
//it means someObj has the method
}

Resources