How do I add properties to a closure? - groovy

When I try to add a property to a custom Closure class...
class MyClosure extends Closure<Object> {
def myProperty
MyClosure() {
super(null)
}
Object doCall(final Closure inner) {
// do something...
}
}
println new MyClosure().myProperty
I get an error:
java.lang.NullPointerException: Cannot get property 'myProperty' on null object
It seems that this is related to the Closure class that has some behaviour I don't really understand, as when I remove the implements part there's no problem:
class MyClosure {
def myProperty
}
println new MyClosure().myProperty
So what do I need to do when I want to add a property to a custom closure?

You need to change closure resolve strategy:
class MyClosure extends Closure<Object> {
def myProperty = "value"
MyClosure() {
super(null)
}
Object doCall(final Closure inner) {
// do something...
}
}
def closure = new MyClosure()
closure.resolveStrategy = Closure.TO_SELF
println closure.myProperty // value

Related

Invoking a call() method introduced by a trait

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)
}
}

NullPointerException when calling a method on another Groovy class

I have the following two Groovy classes:
Buzz.groovy:
import widgets.Fizz
class Buzz {
def WhistleFeather
def init = { servletContext ->
WhistleFeather.load()
println "WhistleFeather loaded."
}
def destroy = { }
}
WhistleFeather.groovy:
package net.me.myapp
import widgets.Fizz
public class WhistleFeather {
def navMenu
def load() {
println "Loading!"
}
}
When execution gets to the WhistleFeather.load() method call I'm getting a NullPointerException. Can anyone see why?
WhistleFeather#load is an instance method, not a static method. Either call it with new WhistleFeather().load(), or turn it into a static method (static load() { ... }).

How do I delegate methodMissing calls to nested classes?

I'd like to create a DSL with syntax like:
Graph.make {
foo {
bar()
definedMethod1() // isn't missing!
}
baz()
}
Where when the handler for this tree encounters the outermost closure, it creates an instance of some class, which has some defined methods and also its own handler for missing methods.
I figured this would be easy enough with some structure like:
public class Graph {
def static make(Closure c){
Graph g = new Graph()
c.delegate = g
c()
}
def methodMissing(String name, args){
println "outer " + name
ObjImpl obj = new ObjImpl(type: name)
if(args.length > 0 && args[0] instanceof Closure){
Closure closure = args[0]
closure.delegate = obj
closure()
}
}
class ObjImpl {
String type
def methodMissing(String name, args){
println "inner " + name
}
def definedMethod1(){
println "exec'd known method"
}
}
}
But the methodMissing handler interprets the entire closure inside Graph rather than delegating the inner closure to ObjImpl, yielding output:
outer foo
outer bar
exec'd known method
outer baz
How do I scope the missing method call for the inner closure to the inner object that I create?
The easy answer is to set the inner closure's resolveStrategy to "delegate first", but doing that when the delegate defines a methodMissing to intercept all method calls has the effect of making it impossible to define a method outside the closure and call it from inside, e.g.
def calculateSomething() {
return "something I calculated"
}
Graph.make {
foo {
bar(calculateSomething())
definedMethod1()
}
}
To allow for this sort of pattern it's better to leave all the closures as the default "owner first" resolve strategy, but have the outer methodMissing be aware of when there is an inner closure in progress and hand back down to that:
public class Graph {
def static make(Closure c){
Graph g = new Graph()
c.delegate = g
c()
}
private ObjImpl currentObj = null
def methodMissing(String name, args){
if(currentObj) {
// if we are currently processing an inner ObjImpl closure,
// hand off to that
return currentObj.invokeMethod(name, args)
}
println "outer " + name
if(args.length > 0 && args[0] instanceof Closure){
currentObj = new ObjImpl(type: name)
try {
Closure closure = args[0]
closure()
} finally {
currentObj = null
}
}
}
class ObjImpl {
String type
def methodMissing(String name, args){
println "inner " + name
}
def definedMethod1(){
println "exec'd known method"
}
}
}
With this approach, given the above DSL example, the calculateSomething() call will pass up the chain of owners and reach the method defined in the calling script. The bar(...) and definedMethod1() calls will go up the chain of owners and get a MissingMethodException from the outermost scope, then try the delegate of the outermost closure, ending up in Graph.methodMissing. That will then see that there is a currentObj and pass the method call back down to that, which in turn will end up in ObjImpl.definedMethod1 or ObjImpl.methodMissing as appropriate.
If your DSL can be nested more than two levels deep then you'll need to keep a stack of "current objects" rather than a single reference, but the principle is exactly the same.
An alternative approach might be to make use of groovy.util.BuilderSupport, which is designed for tree building DSLs like yours:
class Graph {
List children
void addChild(ObjImpl child) { ... }
static Graph make(Closure c) {
return new GraphBuilder().build(c)
}
}
class ObjImpl {
List children
void addChild(ObjImpl child) { ... }
String name
void definedMethod1() { ... }
}
class GraphBuilder extends BuilderSupport {
// the various forms of node builder expression, all of which
// can optionally take a closure (which BuilderSupport handles
// for us).
// foo()
public createNode(name) { doCreate(name, [:], null) }
// foo("someValue")
public createNode(name, value) { doCreate(name, [:], value) }
// foo(colour:'red', shape:'circle' [, "someValue"])
public createNode(name, Map attrs, value = null) {
doCreate(name, attrs, value)
}
private doCreate(name, attrs, value) {
if(!current) {
// root is a Graph
return new Graph()
} else {
// all other levels are ObjImpl, but you could change this
// if you need to, conditioning on current.getClass()
def = new ObjImpl(type:name)
current.addChild(newObj)
// possibly do something with attrs ...
return newObj
}
}
/**
* By default BuilderSupport treats all method calls as node
* builder calls. Here we change this so that if the current node
* has a "real" (i.e. not methodMissing) method that matches
* then we call that instead of building a node.
*/
public Object invokeMethod(String name, Object args) {
if(current?.respondsTo(name, args)) {
return current.invokeMethod(name, args)
} else {
return super.invokeMethod(name, args)
}
}
}
The way BuilderSupport works, the builder itself is the closure delegate at all levels of the DSL tree. It calls all its closures with the default "owner first" resolve strategy, which means that you can define a method outside the DSL and call it from inside, e.g.
def calculateSomething() {
return "something I calculated"
}
Graph.make {
foo {
bar(calculateSomething())
definedMethod1()
}
}
but at the same time any calls to methods defined by ObjImpl will be routed to the current object (the foo node in this example).
There are at least two problems with this approach:
Defining ObjImpl within the same context as Graph means that any missingMethod call will hit Graph first
Delegation appears to happen locally unless a resolveStrategy is set, e.g.:
closure.resolveStrategy = Closure.DELEGATE_FIRST

Type of 'return this' in a Groovy #Mixin

I have a mixin class that bundles functionality for different types that do not share a common heritage. The mixing is applied using the #Mixin annotation, so it is handled at compile time.
Some of the mixin methods return this as the result of a method call. The problem is that the this is of the mixing type and not the type of the base class. When I want to work typed in the rest of the application a ClassCastException is thrown saying that the mixing type can not be cast to the base type.
In the example code below return this returns an object of type AMixin instead of an Object of type BaseClass.
How can I have return this return an object of type BaseClass instead of an object of type AMixin?
class AMixin {
def getWhatIWant(){
if(isWhatIwant){
return this
} else {
getChildWhatIWant()
}
}
def getChildWhatIWant(){
for (def child in childred) {
def whatIWant = child.getWhatIWant()
if (whatIWant) {
return whatIWant
}
}
return null
}
}
#Mixin(AMixin)
class BaseClass {
boolean isWhatiWant
List<baseClass> children
}
I just ran into this same situation. I solved it by setting 'this' from the concrete class into a private variable 'me' inside the concrete class and return 'me' in the Mixin classes. For example:
class MyMixin {
def mixinMethod() {
// do stuff
return me
}
}
#Mixin(MyMixin)
class MyConcreteClass {
private MyConcreteClass me
MyConcreteClass() {
me = this
}
}
I feel like it's a bit kludgy, but I think it's a lot simpler than this other solution. I personally need the ability to use the same Mixin in multiple classes, and it sounds like this other proposed solution would not allow for that if you cannot assign multiple Categories to a single Mixin class.
I created the class Base added the category to the AMixin Class and the BaseClass extends from Base.....(http://groovy.codehaus.org/Category+and+Mixin+transformations)
Executed this in GroovyConsole I get
BaseClass#39c931fb
class Base {
boolean isWhatIwant
List<BaseClass> children
}
#Category(Base)
class AMixin {
def getWhatIWant(){
if(isWhatIwant){
return this
} else {
getChildWhatIWant()
}
}
def getChildWhatIWant(){
for (def child in children) {
def whatIWant = child.getWhatIWant()
if (whatIWant) {
return whatIWant
}
}
return null
}
}
#Mixin(AMixin)
public class BaseClass extends Base {
}
def b = new BaseClass(isWhatIwant:true)
println b.getWhatIWant()
EDIT just a DummyClass. I know it's very awkward that It works....I'm sure Guillaume Laforge could answer how this works...
class DummyClass {
}
#Category(DummyClass)
class AMixin {
def getWhatIWant(){
if(isWhatIwant){
return this
} else {
getChildWhatIWant()
}
}
def getChildWhatIWant(){
for (def child in children) {
def whatIWant = child.getWhatIWant()
if (whatIWant) {
return whatIWant
}
}
return null
}
}
#Mixin(AMixin)
public class BaseClass extends DummyClass {
boolean isWhatIwant
List<BaseClass> children
}
def b = new BaseClass(isWhatIwant:true)
println b.getWhatIWant()

Groovy methodMissing

I have a closure within an object Foo and inside the closure i define a method called 'myStaticMethod' that I want to resolve once the closure is called outside the object Foo. I also happen to have 'on purpose' a static method within my object Foo with the same name. When I call the closure i set the 'resolve strategy' to DELEGATE_ONLY to intercept the call to myStaticMethod that is defined within the closure.
I tried to achieve that through missingMethod but the method is never intercepted. When i make the Foo.myStaticMethod non static, the method is intercepted. I don't quite understand why this is happening though my resolve strategy is set to DELEGATE_ONLY. having the Foo.myStaticMethod static or not shouldn't matter or I am missing something
class Foo {
static myclosure = {
myStaticMethod()
}
static def myStaticMethod() {}
}
class FooTest {
def c = Foo.myclosure
c.resolveStrategy = Closure.DELEGATE_ONLY
c.call()
def missingMethod(String name, def args) {
println $name
}
}
To solve the problem, I ended up overriding the invokeMethod right before calling the closure in FooTests
Foo.metaClass.'static'.invokeMethod = { String name, args ->
println "Static Builder processing $name "
}
While trying to solve this problem, i discovered a very weird way to intercept missing static methods. Might be useful to some of you in the future.
static $static_methodMissing(String name, args) {
println "Missing static $name"
}
-Ken
Static methods unfortunately aren't intercepted by the closure property resolution. The only way that I know to intercept those is to override the static metaClass invokeMethod on the class that owns the closure, ex:
class Foo {
static myclosure = {
myStaticMethod()
}
static myStaticMethod() {
return false
}
}
Foo.metaClass.'static'.invokeMethod = { String name, args ->
println "in static invokeMethod for $name"
return true
}
def closure = Foo.myclosure
assert true == closure()

Resources