I'm trying to add a new method to my Groovy class dynamically, following the documentation.
So here is my class which implements the methodMissing method:
class AlexTest {
def methodMissing(String name, args){
println "Method missing is called"
def cachedMethod = { Object[] varArgs ->
println "Hi! ${varArgs}"
}
AlexTest.metaClass."${name}" = cachedMethod
return cachedMethod(args)
}
}
and here is another groovy script which uses my AlexTest class:
def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")
I expect the "Method missing is called" to be called only once - as the method "hi" would have been 'introduced' inside the methodMissing. But, that methodMissing is being called twice, as if the "hi" method never gets introduced to the AlexTest class.
I have also tried to do it differently:
class AlexTest {
AlexTest() {
def mc = new ExpandoMetaClass(AlexTest, false, true)
mc.initialize()
this.metaClass = mc
}
def methodMissing(String name, args){
println "Method missing is called"
def cachedMethod = { Object[] varArgs ->
println "Hi! ${varArgs}"
}
// note that this is calling metaClass inside the instance
this.metaClass."${name}" = cachedMethod
return cachedMethod(args)
}
}
which sort of works, but only for that single instance. So if I create two instances of AlexTest, and call the 'hi' method, I will get two "Method missing is called" message.
Can anyone point me to the documentation which explains this behaviour?
Thanks in advance!
Regards,
Alex
Add the following to the beginning of your first attempt:
ExpandoMetaClass.enableGlobally()
It works for me with V 2.0.1
If you prefer to enable on a class instance basis, this post illustrates one way to do it:
class AlexTest {
AlexTest() {
def mc = new ExpandoMetaClass(AlexTest, false, true)
mc.initialize()
this.metaClass = mc
}
def methodMissing(String name, args){
println "Method missing is called"
def cachedMethod = { Object[] varArgs ->
println "Hi! ${varArgs}"
}
this.metaClass."${name}" = cachedMethod
return cachedMethod(args)
}
}
def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")
How about this in the script? This makes sure the methodMissing is implemented for the Class reference and is applied to all of the instances referring to it.
class AlexTest {
}
mc = AlexTest.metaClass
mc.methodMissing = {String name, args=[:] ->
println "Method missing is called"
def cachedMethod = { Object[] varArgs ->
println "Hi! ${varArgs}"
}
mc."${name}" = cachedMethod
cachedMethod(args)
}
def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")
def myTest = new AlexTest()
myTest.hi("Walter")
myTest.hi("Hank")
//Prints
Method missing is called
Hi! [Alex]
Hi! [John]
Hi! [Walter]
Hi! [Hank]
Although enabling ExpandoMetaClass globally works as well with a cost of little extra memory. :)
Another solution is caching the method closures in a Map.
class AlexTest {
static Map methods = [:]
def methodMissing(String name, args){
if (!methods[name]) {
println "Method is not cached"
methods[name] = { Object[] varArgs ->
println "Hi! ${varArgs}"
}
}
return methods[name](args)
}
}
def alexTest = new AlexTest()
alexTest.hi("Alex")
alexTest.hi("John")
Output
Method is not cached
Hi! [Alex]
Hi! [John]
Related
ok - tried looking /reading and not sure i have an answer to this.
I have a Utility class which wraps a static ConcurrentLinkedQueue internally.
The utility class itself adds some static methods - i dont expect to call new to create an instance of the Utility.
I want to intercept the getProperty calls the utility class - and implement these internally in the class definition
I can achieve this by adding the following to the utility classes metaclass, before i use it
UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure.'Each'
however what i want to do is declare the interception in the class definition itself. i tried this in the class definition - but it never seems to get called
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
i also tried
static def getProperty (String prop) { println "accessed $prop"}
but this isnt called either.
So other than adding to metaClass in my code/script before i use, how can declare the in the utility class that want to capture property accesses
the actual class i have looks like this at present
class UnitOfMeasure {
static ConcurrentLinkedQueue UoMList = new ConcurrentLinkedQueue(["Each", "Per Month", "Days", "Months", "Years", "Hours", "Minutes", "Seconds" ])
String uom
UnitOfMeasure () {
if (!UoMList.contains(this) )
UoMList << this
}
static list () {
UoMList.toArray()
}
static getAt (index) {
def value = null
if (index in 0..(UoMList.size() -1))
value = UoMList[index]
else if (index instanceof String) {
Closure matchClosure = {it.toUpperCase().contains(index.toUpperCase())}
def position = UoMList.findIndexOf (matchClosure)
if (position != -1)
value = UoMList[position]
}
value
}
static def propertyMissing (receiver, String propName) {
println "prop $propName, saught"
}
//expects either a String or your own closure, with String will do case insensitive find
static find (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def inlist = UoMList.find (matchClosure)
}
static findWithIndex (match) {
Closure matchClosure
if (match instanceof Closure)
matchClosure = match
else if (match instanceof String) {
matchClosure = {it.toUpperCase().contains(match.toUpperCase())}
}
def position = UoMList.findIndexOf (matchClosure)
position != -1 ? [UoMList[position], position] : ["Not In List", -1]
}
}
i'd appreciate the secret of doing this for a static utility class rather than instance level property interception, and doing it in class declaration - not by adding to metaClass before i make the calls.
just so you can see the actual class, and script that calls - i've attached these below
my script thats calling the class looks like this
println UnitOfMeasure.list()
def (uom, position) = UnitOfMeasure.findWithIndex ("Day")
println "$uom at postition $position"
// works UnitOfMeasure.metaClass.static.propertyMissing = {name -> println "accessed prop called $name"}
println UnitOfMeasure[4]
println UnitOfMeasure.'Per'
which errors like this
[Each, Per Month, Days, Months, Years, Hours, Minutes, Seconds]
Days at postition 2
Years
Caught: groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
groovy.lang.MissingPropertyException: No such property: Per for class: com.softwood.portfolio.UnitOfMeasure
Possible solutions: uom
at com.softwood.scripts.UoMTest.run(UoMTest.groovy:12)
Static version of propertyMissing method is called $static_propertyMissing:
static def $static_propertyMissing(String name) {
// do something
}
This method gets invoked by MetaClassImpl at line 1002:
protected static final String STATIC_METHOD_MISSING = "$static_methodMissing";
protected static final String STATIC_PROPERTY_MISSING = "$static_propertyMissing";
// ...
protected Object invokeStaticMissingProperty(Object instance, String propertyName, Object optionalValue, boolean isGetter) {
MetaClass mc = instance instanceof Class ? registry.getMetaClass((Class) instance) : this;
if (isGetter) {
MetaMethod propertyMissing = mc.getMetaMethod(STATIC_PROPERTY_MISSING, GETTER_MISSING_ARGS);
if (propertyMissing != null) {
return propertyMissing.invoke(instance, new Object[]{propertyName});
}
} else {
// .....
}
// ....
}
Example:
class Hello {
static def $static_propertyMissing(String name) {
println "Hello, $name!"
}
}
Hello.World
Output:
Hello, World!
I have a class something like this
class SomeClass () {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos()}
}
what i'd like to be able to do is do implicit Class constructor like this
SomeClass myInst = {println "hello there}
myInst()
but that doesn't work and throws cast exception. you can make this work by writing [] round the closure to call the constructor. but its not pretty
SomeClass myInst = [{println "hello there}] // or myInst = new ({println "hello there}
myInst()
is there a nice way to create the object through assignment and have that closure stored automatically on the created class instance?
feel i'm missing some groovy syntax here that would sort this (PS i'd prefer not having to extend Closure if i can avoid that )
based on the input provided so far i provided an extended script to show the various options. I tried to add an asType closure to Closure and try and call {...} as SomeClass - but if i tried that the asType is never called so groovy must be using another mechanism when you try a coercion
class SomeClass {
Closure instClos
SomeClass (Closure clos) {
println "\tSomeClass constructor: Will constructor called"
instClos = clos
}
def call() {
println "\tSomeClass.call: calling closure "
return (instClos() + "!")
}
SomeClass asType (Closure clos) {
new SomeClass (instClos: clos)
}
}
//this will call the map constructor - needs to be explicitly provided
SomeClass me = [{println "map style construction"; "echo"}]
assert me() == "echo!"
//use new to get class instance with constructor
me = new SomeClass ({println "new SomeClass () construction"; "echo"})
assert me() == "echo!"
//using layered closure approach - doesnt read well though
def someClos = {new SomeClass(it)}
def c = someClos {println "trying layered closure ";"echo"}
assert c() == "echo!"
//extending the Closure class to add a method
ExpandoMetaClass.enableGlobally()
Closure.metaClass.some = {
if (it == SomeClass) {
new SomeClass (delegate)
}
}
//this will call .some() on closure
me = {println "hello will using .some() "; "echo"}.some ( SomeClass)
assert me() == "echo!"
I'm not aware of anyway to auto-coerce a closure. Even though groovy has closure coercion, it works by changing the closure's type, but it's still a closure, and is not layered. Some ideas:
1. Constructor
class SomeClass {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos() + "!"}
}
def c = new SomeClass( { "echo" } )
assert c() == "echo!"
2. Map constructor
class SomeClass {
Closure instClos
def call() {instClos() + "!"}
}
SomeClass c = [instClos: { "echo" }]
assert c() == "echo!"
3. Closure metaprogramming
(Needs enableGlobally())
ExpandoMetaClass.enableGlobally()
Closure.metaClass.some = { new SomeClass(delegate) }
def c = { "echo" }.some()
assert c() == "echo!"
4. Another closure layering
class SomeClass {
Closure instClos
SomeClass (Closure clos) { instClos = clos} //constructor
def call() {instClos() + "!"}
}
def some = { new SomeClass(it) }
def c = some { "echo" }
assert c() == "echo!"
5. Override Closure's asType
ExpandoMetaClass.enableGlobally()
def asType = Closure.metaClass.asType
Closure.metaClass.asType = { Class c ->
(c == SomeClass) ? new SomeClass(delegate) : asType(c)
}
def c = { "echo" } as SomeClass
assert c() == "echo!"
If you have enough flexibility in your design you TRULY only need one method, SomeClass.call(), then you could specify it as an interface instead:
interface SomeClass {
def call()
}
Groovy long ago anticipated the case that Java 8 formalizes with the #FunctionalInterface annotation. If you assign a Groovy Closure to variable or formal parameter of interface type, where the interface has only one method (like SomeClass as defined above), the Groovy compiler will coerce the closure into an instance of that interface. So, given the interface declaration above, the following code:
SomeClass myInst = { println "hello there" }
myInst()
prints "hello there".
I'm seeing a rather strange thing with the new Groovy trait implementation. I have a (single method interface) class that implements a call() method so I can call call its only method just like a closure: instance() instead of having to do instance.call() . However as soon as I introduce such a reference (a Callable) using a trait that breaks. Anyone who can give a hint if this is something that is as expected or is there a workaround to that?
class MethodCallSpec extends Specification {
def "call a callable"() {
expect:
def thing = new Callable()
"hello" == thing.call("hello")
}
def "call a callable like a closure"() {
expect:
def thing = new Callable()
"hello" == thing("hello")
}
def "call with callable"() {
expect:
def thing = new SomethingWithCallable()
"hello" == thing.doSomething("hello")
}
}
class Callable {
Object call(def message) {
message
}
}
trait WithCallable {
Callable callable = new Callable();
}
class SomethingWithCallable implements WithCallable {
def doSomething(def message) {
callable(message) // this breaks unless written as callable.call(message)
}
}
I'd like to create a simple wrapper, which would allow calling objects methods as a fluent interface. I've been thinking about rewriting methods of a class upon creation, but this doesn't seem to work. Is this possible in some way with groovy metaprograming?
I have this kind of code snippet so far:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
delegate.class.getMethods().each { method ->
def name = method.getName()
FluentWrapper.metaClass."$name" = { Object[] varArgs ->
method.invoke(wrapped, name, varArgs)
return this
}
}
}
def methodMissing(String name, args) {
def method = delegate.getClass().getDeclaredMethods().find { it.match(name) }
if(method) {
method.invoke(delegate,name, args)
return FluentWrapper(delegate)
}
else throw new MissingMethodException(name, delegate, args)
}
}
Assuming example Java class:
class Person {
void setAge()
void setName()
}
I'd like to be able to execute the following piece of code:
def wrappedPerson = new FluentWrapper(new Person())
wrappedPerson.setAge().setName()
I'm using Groovy 1.6.7 for this.
This is all Groovy, and I'm using 1.8.6 (the current latest), but given this Person Class:
class Person {
int age
String name
public void setAge( int age ) { this.age = age }
public void setName( String name ) { this.name = name }
public String toString() { "$name $age" }
}
And this FluentWrapper class:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
}
def methodMissing(String name, args) {
def method = delegate.getClass().declaredMethods.find { it.name == name }
if(method) {
method.invoke( delegate, args )
return this
}
else throw new MissingMethodException(name, delegate, args)
}
}
Then, you should be able to do:
def wrappedPerson = new FluentWrapper(new Person())
Person person = wrappedPerson.setAge( 85 ).setName( 'tim' ).delegate
And person should have the age and name specified
I find #tim_yates' answer nice, but you couldn't access delegate methods' return values (something one usually likes doing, even for Builders in the case of build() :)
Moreover, if this wasn't intended for a Builder but for an object with a chainable interface (like that of jQuery wrapped objects in JS), it would be a serious issue.
So I'd put the wrapper like this:
class FluentWrapper {
def delegate
FluentWrapper(wrapped) {
delegate = wrapped
}
def methodMissing(String name, args) {
def method = delegate.getClass().declaredMethods.find { it.name == name }
if(method) {
def result = method.invoke(delegate, args)
return result != null ? result : this
}
else throw new MissingMethodException(name, delegate, args)
}
}
Note the elvis operator is unsuitable since a falsy value would never get returned.
Of course, it's up to the invoker to know wether a method is chainable or not, but that could be overcome with method annotations if neccesary.
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
}