i knewt how to add method to metaClass of java.util.List :
java.util.List.metaClass.average={
return delegate.sum()/delegate.size();
}
and if i have def myList=[new Person(score:1),new Person(score:2)] , i call to new method as following:
myList.average();
However, i want to call it as following :
myList.average{it.score}
How can i add this method to metaClass to be called as Closure( {} and not ())
You should be able to do:
List.metaClass.average = { Closure c ->
delegate.sum( c ) / delegate.size()
}
Related
I am trying to use call operator () overloading, but it does not work on class fields. What's wrong?
class Foo {
void call(int x){
println("x="+x)
}
}
class MyCallable {
Foo foo = new Foo()
}
Foo foo = new Foo()
foo(5) //works
MyCallable mc = new MyCallable()
mc.foo(2) //not works
But program terminated with exception:
Exception in thread "main" groovy.lang.MissingMethodException: No
signature of method: mpctests.MyCallable.foo() is applicable for
argument types: (java.lang.Integer) values: [2]
You get MissingMethodException when you call mc.foo(5), because Groovy's invoke object method mechanism gets triggered. There is one thing worth explaining to get a better understanding about this situation. Your MyCallable class:
class MyCallable {
Foo foo = new Foo()
}
gets compiled to something like this:
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class MyCallable implements GroovyObject {
private Foo foo;
public MyCallable() {
CallSite[] var1 = $getCallSiteArray();
Object var2 = var1[0].callConstructor(Foo.class);
this.foo = (Foo)ScriptBytecodeAdapter.castToType(var2, Foo.class);
MetaClass var3 = this.$getStaticMetaClass();
this.metaClass = var3;
}
public Foo getFoo() {
return this.foo;
}
public void setFoo(Foo var1) {
this.foo = var1;
}
}
Groovy also compiles every field access like mc.foo to a getter method call mc.getFoo(). So when you call mc.foo(5) it is clear for Groovy runtime that you expect to call a foo(5) method on mc object. And this method does not exist and MissingMethodException gets thrown.
However, it works if you create object def foo = new Foo() and then you call foo(5), because foo is an object and foo(5) is a strict instruction to invoke call(5) method on foo object (foo(5) is a shorthand version of foo.call(5)). The same situation would take place if you call mc() - Groovy would try to invoke mc.call() method. But when you say mc.foo(5) it's clear that you are trying to invoke foo(5) method.
If you want to use call operator on mc.foo field there are two options:
1. Use direct field access operator #
mc.#foo(5)
In this case you refer directly to foo field and you can use shorthand call operator.
2. Use with {} method
mc.with {
foo(5)
}
In this case it is also a straightforward for Groovy runtime that you are accessing foo field and you can use call operator on it.
Alternatives
Using getter method:
mc.getFoo()(5)
Using method call() directly:
mc.foo.call(5) // equivalent of mc.getFoo().call(5)
I am using groovy as an extension language in my application. The constructor of the class which a script extend accepts variable arguments. When I try to instantiate the groovy class, I get an java.lang.ArrayIndexOutOfBoundsException from the super() call in the constructor. The issue can easily be reproduced in a standalone groovy script:
// problem.groovy
class A {
A(float ... more) {}
}
class B extends A {
B() {
super();
}
}
new B();
when run, this produces:
$ groovy problem.groovy
Caught: java.lang.ArrayIndexOutOfBoundsException: 0
java.lang.ArrayIndexOutOfBoundsException: 0
at B.<init>(problem.groovy:7)
at problem.run(problem.groovy:11)
line 7 is the super() call in class B.
Is this a bug in the language itself? I couldn't find any other mention of it online. I'm new to Groovy and I may well not be understanding some subtlety of the language. At the very least, it seems like this should throw a compiler error when loading the script.
You can use #InheritConstructors AST to avoid this boilerplate code.
class A {
A(float ... more) {}
}
#groovy.transform.InheritConstructors
class B extends A {}
new B()
Moreover, in your example wouldn't you provide a default constructor in A (since it is being overloaded) and then use super() in B's constructor. Or initialize the overloaded constructors args to null.
class A {
A(){println 'default'}
//Or use A(float... more = null) {println 'varargs'}
//instead of default constructor
A(float... more) {println 'varargs'}
}
class B extends A {
B(){
super()
}
}
new B()
//Uses default constructor A() if overloaded
//constructor is not initialized to null
It seems to be calling a nonexistent constructor with super() - call it even with a null or put a no arg constructor in A and it works.
It appears that the variable arg constructor on the superclass isn't matching. Fun.
At runtime I'm grabbing a list of method names on a class, and I want to invoke these methods. I understand how to get the first part done from here:
http://docs.codehaus.org/display/GROOVY/JN3535-Reflection
GroovyObject.methods.each{ println it.name }
What I can't seem to find information on is how to then invoke a method once I've grabbed its name.
What I want is to get here:
GroovyObject.methods.each{ GroovyObject.invokeMethod( it.name, argList) }
I can't seem to find the correct syntax. The above seems to assume I've overloaded the default invokeMethod for the GroovyObject class, which is NOT the direction I want to go.
Once you get a MetaMethod object from the metaclass, you can call invoke on it. For example:
class MyClass {
def myField = 'foo'
def myMethod(myArg) { println "$myField $myArg" }
}
test = new MyClass()
test.metaClass.methods.each { method ->
if (method.name == 'myMethod') {
method.invoke(test, 'bar')
}
}
Alternatively, you can use the name directly:
methodName = 'myMethod'
test."$methodName"('bar')
Groovy allows for dynamic method invocation as well as dynamic arguments using the spread operator:
def dynamicArgs = [1,2]
def groovy = new GroovyObject()
GroovyObject.methods.each{
groovy."$it.name"(staticArg, *dynamicArgs)
}
Reference here
Question answered here.
I am trying to take advantage of the convenience of groovy's scripting syntax to assign properties, but having trouble with a specific case. I must be missing something simple here. I define class A, B, C as so:
class A {
A() {
println "Constructed class A!"
}
}
class B {
B() {
println "Constructed class B!"
}
}
class C {
private member
C() {
println "Constructed class C!"
}
def setMember(A a) {
println "Called setMember(A)!"
member = a
}
def setMember(B b) {
println "Called setMember(B)!"
member = b
}
}
And then try the following calls in a script:
c = new C()
c.setMember(new A()) // works
c.member = new A() // works
c.setMember(new B()) // works
c.member = new B() // doesn't work!
The last assignment results in an error: 'Cannot cast object of class B to class A". Why doesn't it call the proper setMember method for class B like it does for class A?
The shortcut of using the dot notation for calling a property's setter method doesn't do type checking. Instead it seems to use the first entry in the list of methods with a given name and invoke it.
You can also read Pyrasun's extended comments on the shortcomings of Groovy's property handling.
If you want to bypass this (mis)behavior you have to call the setter directly, as Groovy supports type checking for method calls. Alternatively you could also access the field directly without a setter using
c.#member = new B()
or you do the type checking on your own in a single setter method:
def setMember(def param) {
if (param instanceof A) println "Called setMember(A)!"
if (param instanceof B) println "Called setMember(B)!"
member = param
}
If for example I have a class named A. Can I make an object be callable, just like Python does? For example :
def myObject = new A()
myObject()
and that would call some object method. Can it be done?
In Groovy only closures are callable by default. E.g. Classes are not callable out of the box. If necessary you can dynamically add a call method to a type's ExpandoMetaClass to make all instances of that type callable.
Hint: you can try out all code sample using the GroovyConsole
Closures are callable by default in Groovy:
// A closure
def doSomething = { println 'do something'}
doSomething()
// A closure with arguments
def sum = {x, y -> x + y}
sum(5,3)
sum.call(5,3)
// Currying
def sum5 = sum.curry(5)
sum5(3)
To make all instances of a specific type callable you can dynamically add a call method to its meta class:
MyObject.metaClass.call = { prinlnt 'I was called' }
def myObject = new MyObject()
myObject()
If you rather only make a specific instance callable you can dynamically add a call method to its meta class:
def myObject = new MyObject()
myObject.metaClass.call = { println 'Called up on' }
myObject()