Create embedded instances dynamically during navigation - groovy

I am really digging groovy's ability to navigate hierarchies of objects elegantly using the dot notation.
One question I have, is there a way to create embedded objects elegantly as well during navigation. For instance, given the following classes:
class Bar {
int a
}
class Foo {
Bar b
}
I want to be able to do this:
Foo f = new Foo()
f.b.a = 4
Currently, I have to do:
Foo f = new Foo()
f.b = new Bar()
f.b.a = 4
Note that I need f.b to be null unless it has been set via navigation or otherwise. So blindly instantiating b = new Bar() within the class Foo does not meet the needs of the requirement.

You may use null safe operator ?. Or override a getter for b in Foo and if it's null set new instance of b in Foo and return it.
It would be:
class Foo {
Bar b
Bar getB() {
if(b == null)
this.#b = new Bar()
b
}
}

You could initialize the entire hierarchy in a single line, like so:
Foo f = new Foo(b: new Bar(a: 4))

Related

In Groovy, how to get annotation values for parameters inside closures?

For example, given this groovy code:
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.ElementType
import java.lang.annotation.Target
#Target([ElementType.PARAMETER])
#Retention(RetentionPolicy.RUNTIME)
#interface Bar {
String qux() default ""
}
def closure1 = { #Bar(qux = 'zxv') String foo ->
println foo
}
println "[value for qux]"
How would you print the value for qux (which in this case is 'zxv') ?
Reflection API can give you what you're looking for (I'm using Groovy 2.5 on Java 8).
The closure is essentially a method named call on a Closure instance, and parameterAnnotations[0][0] is a quick way of getting that method's first parameter's first annotation.
def anno = closure1.class.methods.find { it.name == 'call' }.parameterAnnotations[0][0]
println anno.qux() // prints zxv

Using MetaProgramming to Add collectWithIndex and injectWithIndex similar to eachWithIndex

Please help with a metaprogramming configuration such that I can add collections methods called collectWithIndex and injectWithIndex that work in a similar manner to eachWithIndex but of course include the base functionality of collect and inject. The new methods would accept a two (three with maps) argument closure just like eachWithIndex. I would like to have the capability to utilize these methods across many different scripts.
Use case:
List one = [1, 2, 3]
List two = [10, 20, 30]
assert [10, 40, 90] == one.collectWithIndex { value, index ->
value * two [index]
}
Once the method is developed then how would it be made available to scripts? I suspect that a jar file would be created with special extension information and then added to the classpath.
Many thanks in advance
I'm still sure, it's not a proper SO question, but I'll give you an example, how you can enrich metaclass for your multiple scripts.
Idea is based on basescript, adding required method to List's metaClass in it's constructor. You have to implement collect logic yourself, through it's pretty easy. You can use wrapping
import org.codehaus.groovy.control.CompilerConfiguration
class WithIndexInjector extends Script {
WithIndexInjector() {
println("Adding collectWithIndex to List")
List.metaClass.collectWithIndex {
int i = 0
def result = []
for (o in delegate) // delegate is a ref holding initial list.
result << it(o, i++) // it is closure given to method
result
}
}
#Override Object run() {
return null
}
}
def configuration = new CompilerConfiguration()
configuration.scriptBaseClass = WithIndexInjector.name
new GroovyShell(configuration).evaluate('''
println(['a', 'b'].collectWithIndex { it, id -> "[$id]:$it" })
''')
// will print [[0]:a, [1]:b]
If you like to do it in more functional way, without repeating collect logic, you may use wrapping proxy closure. I expect it to be slower, but maybe it's not a deal. Just replace collectWithIndex with following implementation.
List.metaClass.collectWithIndex {
def wrappingProxyClosure = { Closure collectClosure, int startIndex = 0 ->
int i = startIndex
return {
collectClosure(it, i++) // here we keep hold on outer collectClosure and i, and use call former with one extra argument. "it" is list element, provided by default collect method.
}
}
delegate.collect(wrappingProxyClosure(it))
}
offtopic: In SO community your current question will only attract minuses, not answers.

How do I use groovy's AS keyword

This may be a duplicate but "as" is an INCREDABLY hard keyword to google, even S.O. ignores "as" as part of query.
So I'm wondering how to implement a class that supports "as" reflexively. For an example class:
class X {
private val
public X(def v) {
val=v
}
public asType(Class c) {
if (c == Integer.class)
return val as Integer
if(c == String.class)
return val as String
}
}
This allows something like:
new X(3) as String
to work, but doesn't help with:
3 as X
I probably have to attach/modify the "asType" on String and Integer somehow, but I feel any changes like this should be confined to the "X" class... Can the X class either implement a method like:
X fromObject(object)
or somehow modify the String/Integer class from within X. This seems tough since it won't execute any code in X until X is actually used... what if my first usage of X is "3 as X", will X get a chance to override Integer's asType before Groovy tries to call is?
As you say, it's not going to be easy to change the asType method for Integer to accept X as a new type of transformation (especially without destroying the existing functionality).
The best I can think of is to do:
Integer.metaClass.toX = { -> new X( delegate ) }
And then you can call:
3.toX()
I can't think how 3 as X could be done -- as you say, the other way; new X('3') as Integer is relatively easy.
Actually, you can do this:
// Get a handle on the old `asType` method for Integer
def oldAsType = Integer.metaClass.getMetaMethod( "asType", [Class] as Class[] )
// Then write our own
Integer.metaClass.asType = { Class c ->
if( c == X ) {
new X( delegate )
}
else {
// if it's not an X, call the original
oldAsType.invoke( delegate, c )
}
}
3 as X
This keeps the functionality out of the Integer type, and minimizes scope of the effect (which is good or bad depending on what you're looking for).
This category will apply asType from the Integer side.
class IntegerCategory {
static Object asType(Integer inty, Class c) {
if(c == X) return new X(inty)
else return inty.asType(c)
}
}
use (IntegerCategory) {
(3 as X) instanceof X
}

How do I create and access the global variables in Groovy?

I need to store a value in a variable in one method and then I need to use that value from that variable in another method or closure. How can I share this value?
In a Groovy script the scoping can be different than expected. That is because a Groovy script in itself is a class with a method that will run the code, but that is all done runtime. We can define a variable to be scoped to the script by either omitting the type definition or in Groovy 1.8 we can add the #Field annotation.
import groovy.transform.Field
var1 = 'var1'
#Field String var2 = 'var2'
def var3 = 'var3'
void printVars() {
println var1
println var2
println var3 // This won't work, because not in script scope.
}
def i_am_not_global = 100 // This will not be accessible inside the function
i_am_global = 200 // this is global and will be even available inside the
def func()
{
log.info "My value is 200. Here you see " + i_am_global
i_am_global = 400
//log.info "if you uncomment me you will get error. Since i_am_not_global cant be printed here " + i_am_not_global
}
def func2()
{
log.info "My value was changed inside func to 400 . Here it is = " + i_am_global
}
func()
func2()
here i_am_global variable is a global variable used by func and then again available to func2
if you declare variable with def it will be local, if you don't use def its global
class Globals {
static String ouch = "I'm global.."
}
println Globals.ouch
Like all OO languages, Groovy has no concept of "global" by itself (unlike, say, BASIC, Python or Perl).
If you have several methods that need to share the same variable, use a field:
class Foo {
def a;
def foo() {
a = 1;
}
def bar() {
print a;
}
}
Just declare the variable at class or script scope, then access it from inside your methods or closures. Without an example, it's hard to be more specific for your particular problem though.
However, global variables are generally considered bad form.
Why not return the variable from one function, then pass it into the next?
I think you are talking about class level variables.
As mentioned above using global variable/class level variables are not a good practice.
If you really want to use it. and if you are sure that there will not be impact...
Declare any variable out side the method. at the class level with out the variable type
eg:
{
method()
{
a=10
print(a)
}
// def a or int a wont work
a=0
}
def sum = 0
// This method stores a value in a global variable.
def add =
{
input1 , input2 ->
sum = input1 + input2;
}
// This method uses stored value.
def multiplySum =
{
input1 ->
return sum*input1;
}
add(1,2);
multiplySum(10);
Could not figure out what you want, but you need something like this ? :
​def a = { b -> b = 1 }
​bValue = a()
println b // prints 1
Now bValue contains the value of b which is a variable in the closure a. Now you can do anything with bValue Let me know if i have misunderstood your question

How do I enumerate all the defined variables in a groovy script

I have a groovy script with an unknown number of variables in context at runtime, how do I find them all and print the name and value of each?
Well, if you're using a simple script (where you don't use the "def" keyword), the variables you define will be stored in the binding and you can get at them like this:
foo = "abc"
bar = "def"
if (true) {
baz = "ghi"
this.binding.variables.each {k,v -> println "$k = $v"}
}
Prints:
foo = abc
baz = ghi
args = {}
bar = def
I'm not aware of an easy way to enumerate through the variables defined with the "def" keyword, but I'll be watching this question with interest to see if someone else knows how.
Actually, Ted's answer will also work for 'def'ed variables.
def foo = "abc"
def bar = "def"
if (true) {
baz = "ghi"
this.binding.variables.each {k,v -> println "$k = $v"}
}
yields
baz = ghi
__ = [null, null, null]
foo = abc
_ = null
bar = def
I'm not sure what the _-variables signify, but I'm sure you can work around them.
Groovy Object contains method - dump()
https://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Object.html
String dump()
Generates a detailed dump string of an object showing its class, hashCode and fields.
Example:
class MyClass {
def foo = "abc"
def bar = "def"
}
println(new MyClass().dump())
stdout: <MyClass#1fa268de foo=abc bar=def>

Resources