groovy generic fluent builder - groovy

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.

Related

What is the static version of propertyMissing method in Groovy?

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!

Groovy call field

I'm trying to put into the field an object that supports a call operation, and then to call him. I can do it without intermediate reading fields in a variable?
My attempt looks like this:
class CallableObjectDynamic {
def call() {
return "5"
}
}
class MyClassDynamic {
CallableObjectDynamic field = new CallableObjectDynamic()
}
class GroovyRunnerDynamic {
static String make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field()
}
}
​
But I receive groovy.lang.MissingMethodException.
What can you do? Or can anyone give a proof where it's written that we can't call the field?
Membership (.) has lower order of precedence than function/method/call invocation (()). Thus this line:
return x.field()
is interpreted as "invoke the 'field' method on the 'x' object".
To get Groovy to parse the code as you desire, the minimal change would be to regroup using parentheses, as follows:
return (x.field)()
which is (ultimately) interpreted as "invoke the 'call' method on the 'field' object member of the 'x' object", as desired.
It is trivial issue. Not required to have parenthesis for field.
Change from:
return x.field()
To:
return x.field
If you want to execute call method further, then use below code snippet.
Note that static method return type is changed.
class CallableObjectDynamic {
def call() {
return "5"
}
}
class MyClassDynamic {
CallableObjectDynamic field = new CallableObjectDynamic()
}
class GroovyRunnerDynamic {
static def make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field
}
}
​GroovyRunnerDynamic.make(1)​.call()​
Output would be : 5
Not sure why argument to make method is done here, seems to be not used in the above code.
Alternatively, you can change
class GroovyRunnerDynamic {
static def make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
return x.field.call()
}
}
​GroovyRunnerDynamic.make(1)
EDIT: Based on OP's implicit call.
Not really sure how it is working, but the below does implicit call. Just assign x.field to a variable and just add parenthesis for that as shown below.
class GroovyRunnerDynamic {
static String make(int arg1) {
MyClassDynamic x = new MyClassDynamic()
def fun = x.field
fun()
}
}
GroovyRunnerDynamic.make(1)

Changing and adding arguments of method before invocation

I want to reproduce the behavior of the default arguments by intercepting the call to some methods. The following code tries to give a default argument when the method display is called without arguments:
class Thing
{
void display(String text)
{
println(text)
}
def invokeMethod(String name, args)
{
if(name == "display" && args.length == 0)
{
metaClass.getMetaMethod(name, ["some text"]).
invoke(this, "some text")
}
else
{
metaClass.getMetaMethod(name, args).
invoke(this, args)
}
}
}
Thing thing = new Thing()
thing.display("stuff") //prints "stuff"
thing.display() //nothing happens
However, this does not work; nothing is printed when no argument is given.
This example is not very useful but I would want to make it work; my next goal is indeed to create methods whose arguments could be given in their name. Example:
Add1And2()// should return 3
Add4And9()// should return 13
Intercepting the call to these nonexistent methods and calling an existing method that would do the addition using the numbers used in the name of the nonexistent methods would make it possible...
Class Thing should implement GroovyInterceptable as below to make invokeMethod work:
class Thing implements GroovyInterceptable {
void display(String text) {
println(text)
}
def invokeMethod(String name, args) {
if(name == "display" && args.length == 0) {
metaClass.getMetaMethod(name).invoke(this, "some text")
} else {
metaClass.getMetaMethod(name, args).invoke(this, args)
}
}
}
Thing thing = new Thing()
thing.display("stuff") //prints "stuff"
thing.display()

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

Resources