How do I define an entire object and methods on single line - groovy

This throws an error (can't set on null object)
def currentBuild = [:].rawBuild.getCauses = { return 'hudson.model.Cause$UserIdCause#123abc' }
I need to do it on multiple lines like this
def currentBuild = [:]
currentBuild.rawBuild = [:]
currentBuild.rawBuild.getCauses = { return 'hudson.model.Cause$UserIdCause#123abc' }
Is there a terse way to define this object on a single line or statement? I don't understand why my single line attempt doesn't work.

Instead of chaining setters, I'd just use a map literal with the nested
values. E.g.
def currentBuild = [rawBuild: [getCauses: { return 'hudson.model.Cause$UserIdCause#123abc' }]]
println currentBuild.rawBuild.getCauses()
// → hudson.model.Cause$UserIdCause#123abc
If you have to go more imperative instead of declarative, have a look at
.get(key, fallback), .withDefault{ ... }, .tap{ ... }.
BTW: those are not objects but just maps.

Related

How to get a value of a dynamic key in Groovy JSONSlurper?

The variable resp contains below JSON response -
{"name":"sample","address":{"country":"IN","state":"TN","city":"Chennai"}}
I have planned using param1 variable to get the required key from JSON response, but I'm unable to get my expected results.
I'm passing the param1 field like - address.state
def actValToGet(param1){
JsonSlurper slurper = new JsonSlurper();
def values = slurper.parseText(resp)
return values.param1 //values.address.state
}
I'm getting NULL value here -> values.param1
Can anyone please help me. I'm new to Groovy.
The map returned from the JsonSlurper is nested rather than than flat. In other words, it is a map of maps (exactly mirroring the Json text which was parsed). The keys in the first map are name and address. The value of name is a String; the value of address is another map, with three more keys.
In order to parse out the value of a nested key, you must iterate through each layer. Here is a procedural solution to show what's happening.
class Main {
static void main(String... args) {
def resp = '{"name":"sample","address":{"country":"IN","state":"TN","city":"Chennai"}}'
println actValToGet(resp, 'address.state')
}
static actValToGet(String resp, String params){
JsonSlurper slurper = new JsonSlurper()
def values = slurper.parseText(resp)
def keys = params.split(/\./)
def output = values
keys.each { output = output.get(it) }
return output
}
}
A more functional approach might replace the mutable output variable with the inject() method.
static actValToGet2(String resp, String params){
JsonSlurper slurper = new JsonSlurper()
def values = slurper.parseText(resp)
def keys = params.split(/\./)
return keys.inject(values) { map, key -> map.get(key) }
}
And just to prove how concise Groovy can be, we can do it all in one line.
static actValToGet3(String resp, String params){
params.split(/\./).inject(new JsonSlurper().parseText(resp)) { map, key -> map[key] }
}
You may want to set a debug point on the values output by the parseText() method to understand what it's returning.

Strange behaviour of adding dynamic methods on Groovy's NodeChild

I'm using Grails XML Parser to parse an XML string and after getting the parsed NodeChild instance, I'm adding dynamic methods on that instance like below:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
NodeChild result = XML.parse("<root></root>")
result.getMetaClass().methodA = { return "a" }
result.getMetaClass().methodB = { return "b" }
println rootNode.methodA()
println rootNode.methodB()
Now the line where I'm calling methodA() and expecting "a" to be printed, I'm getting MissingMethodException that methodA() not found.
I investigated on this for some time and found that the all dynamic methods getting replaced with the last dynamic method we add, i.e. in this case: methodB() is replacing (or doing something) methodA(), so I call & print methodB() first, it prints "b" properly.
This strikes me to another test as following:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
String result = "any-other-data-type-instance-here-to-inject-dynamic-methods"
result.getMetaClass().methodA = { return "a" }
result.getMetaClass().methodB = { return "b" }
println rootNode.methodA()
println rootNode.methodB()
In this case, both statement prints fine. So the problem is only with the classNodeChild. I'm using exando metaclass feature for long time and I faced such kind of problem. Any idea, that why this is happening?
You need to assign the metaclass methods before the instance is returned, otherwise it will have the old metaclass and not the new one with the new methods. Also, assign to the class, not the instance - I'm not sure if you wanted to only affect this instance's metaclass but that's not the syntax.
This works:
import grails.converters.XML
import groovy.util.slurpersupport.NodeChild
NodeChild.metaClass.methodA = { return "a" }
NodeChild.metaClass.methodB = { return "b" }
NodeChild result = XML.parse("<root></root>")
println result.methodA()
println result.methodB()
Note that you're defining methods with an implicit it argument, but passing nothing, so Groovy passes a null. If you intend for the methods to have no arguments, use this syntax:
NodeChild.metaClass.methodA = { -> return "a" }
NodeChild.metaClass.methodB = { -> return "b" }

Map with default value created in a closure

I want to store objects in a map (called result). The objects are created or updated from SQL rows.
For each row I read I access the map as follows:
def result = [:]
sql.eachRow('SELECT something') { row->
{
// check if the Entry is already existing
def theEntry = result[row.KEY]
if (theEntry == null) {
// create the entry
theEntry = new Entry(row.VALUE1, row.VALUE2)
// put the entry in the result map
result[row.KEY] = theEntry
}
// use the Entry (create or update the next hierarchie elements)
}
I want to minimize the code for checking and updating the map. How can this be done?
I know the function map.get(key, defaultValue), but I will not use it, because it is to expensive to create an instance on each iteration even if I don't need it.
What I would like to have is a get function with a closure for providing the default value. In this case I would have lazy evaluation.
Update
The solution dmahapatro provided is exactly what I want. Following an example of the usage.
// simulate the result from the select
def select = [[a:1, b:2, c:3], [a:1, b:5, c:6], [a:2, b:2, c:4], [a:2, b:3, c:5]]
// a sample class for building an object hierarchie
class Master {
int a
List<Detail> subs = []
String toString() { "Master(a:$a, subs:$subs)" }
}
// a sample class for building an object hierarchie
class Detail {
int b
int c
String toString() { "Detail(b:$b, c:$c)" }
}
// the goal is to build a tree from the SQL result with Master and Detail entries
// and store it in this map
def result = [:]
// iterate over the select, row is visible inside the closure
select.each { row ->
// provide a wrapper with a default value in a closure and get the key
// if it is not available then the closure is executed to create the object
// and put it in the result map -> much compacter than in my question
def theResult = result.withDefault {
new Master(a: row.a)
}.get(row.a)
// process the further columns
theResult.subs.add new Detail(b: row.b, c: row.c )
}
// result should be [
// 1:Master(a:1, subs:[Detail(b:2, c:3), Detail(b:5, c:6)]),
// 2:Master(a:2, subs:[Detail(b:2, c:4), Detail(b:3, c:5)])]
println result
What I learned from this sample:
withDefault returns a wrapper, so for manipulating the map use the wrapper and not the original map
row variable is visible in the closure!
create the wrapper for the map in each iteration again, since row var changed
You asked for it, Groovy has it for you. :)
def map = [:]
def decoratedMap = map.withDefault{
new Entry()
}
It works the same way you would expect it to work lazily. Have a look at withDefault API for a detailed explanation.

runtime invocation of method with arguments in groovy

For simplicity let's say I have code similar to this:
def testMethod(String txt) {
return txt;
}
public String evaluate(String expression) {
//String result = "${testMethod('asdasdasd')}";
String result = "${expression}";
return result;
}
I need the expression value which is passed to method "evaluate" to be executed.
in case of calling
// everything works perfectly well,
String result = "${testMethod('samplestring')}";
in case of calling
// (when expression = testMethod) - everything works perfectly well,
String result = "${expression}"("samplestring");
in case of calling
// (when expression = testMethod('samplestring')) - it's not working.
// I see testMethod('samplestring') as the result, but I need it to be evaluated.
String result = "${expression}"
How can I do that?
Thanks.
Thus should work as well;
Eval.me( "${expression}" )
Edit
As pointed out, this won't work as it stands, you need to pass in the script that contains the method with Eval.x like so:
def testMethod(String txt) {
txt
}
public String evaluate(String expression) {
String result = Eval.x( this, "x.${expression}" )
result
}
println evaluate( "testMethod('samplestring')" )
That will print samplestring
You may use the GroovyShell class for this purpose, but you will need to define a Binding AFAIK. This works in the Groovy Console:
def testMethod(txt) {
"$txt!";
}
def evaluate(String expression) {
def binding = new Binding(['testMethod': testMethod])
new GroovyShell(binding).evaluate(expression)
}
evaluate('testMethod("Hello World")');

How to iterate over groovy class non-static closures and optionally replace them?

I'd like to iterate over groovy class non-static closures and optionally replace them.
I can get MetaClass with something like
MyClassName.metaClass
and from there I can get all properties like
metaClassObject.properties
which is the list of MetaProperty objects.
The problem is that I can't detect which of those properties are closures and which are simple objects. MetaProperty object's type property return Object in both case.
And about replacing: Let's say, I know that it is a closure A, then can I create another closure B that wraps closure A with some optional code and replace that closure A with B in the class definition? Should work like some sort of interceptor.
This is one way I have tried out:
class Test {
def name = 'tim'
def processor = { str ->
"Hello $name $str"
}
}
Test t = new Test()
t.metaClass.properties.each {
if( t[ it.name ].metaClass.respondsTo( it, 'doCall' ) ) {
println "$it.name is a closure"
def old = t[ it.name ]
t.metaClass[ it.name ] = { str ->
"WOO! ${old( str )}"
}
}
}
println t.processor( 'groovy!' ) // prints 'WOO! Hello tim groovy!'
However, it would need expanding as I rely on the fact that I know how many parameters it takes for the patching closure replacement
There may also be a simpler way to do this...

Resources