I got confused with this two lines of coding :
this.class.methods.name
This is called Gpath (Am I right?). Now consider this code :
count = 0
def a = [1,2,3,4,5,5,51,2]
a.findAll { it == 5 }.each { count ++ }
println count
The line:
a.findAll { it == 5 }.each { count ++ }
is called as a method chaining or Gpath?
Literally, I got struck with these two meanings. It will be nice if some one explains the difference between these two.
Thanks in advance.
I'm not sure if I understand the question correctly.
As I see it, in both examples you are using method chaining, simply because you are calling a method in the object that is returned by another method. But, as Arturo mentions, some people confuse method chaining and fluent interfaces. A fluent interface is indeed quite handy if you want to chain methods.
In Groovy, however, you may, instead of coding a fluent interface yourself, use the with method in any object. For example, using the same Person and Address classes that Arturo defined, you can do:
def person = new Person()
person.with {
name = 'John'
age = 25
address = new Address('Boulevard St')
}
assert person.name == 'John' &&
person.age == 25 &&
person.address.name == 'Boulevard St'
Now, GPath, as I understand, is just a way of accessing the properties of an object. For example, if you have the class:
class Foo {
def bar
}
The GPath mechanism in Groovy lets you do things like:
def foo = new Foo(bar: 42)
assert foo.bar == 42
Instead of accessing the bar property with its getter, like foo.getBar(). Nothing too fancy. But other classes in Groovy also have some GPath magic and there is where things get more interesting. For example, lists let you access properties in their elements the same way you'd access normal properties:
def foos = (1..5).collect { new Foo(bar: it) } // Five Foos.
assert foos.bar == [1, 2, 3, 4, 5]
As you can see, accessing the bar property on a list of objects that have that property will result in a list with the values of that property for each object in the list. But if you access a property that the elements of the list don't have, e.g. foos.baz, it will throw a MissingPropertyException.
This is exactly what is happening in:
this.class.methods.name
I, however, consider this behavior to be a little too magic for my taste (unless you are parsing XML, in which case is totally fine). Notice that if the collection returned by the methods method would be some weird collection that had a name property, methods.name would result in that name instead of the names of each method in the collection. In these cases I prefer to use the (IMO) more explicit version:
this.class.methods*.name
Wich will give you the same result, but it's just syntax sugar for:
this.class.methods.collect { it.name }
... and let's the intention of the expression to be more clear (i.e. "I want the names of each method in methods").
Finally, and this is quite off-topic, the code:
count = 0
def a = [1,2,3,4,5,5,51,2]
a.findAll { it == 5 }.each { count ++ }
println count
can be rewritten as:
def a = [1,2,3,4,5,5,51,2]
def count = a.count { it == 5 }
println count
:)
I think that your code is an example of method chaining.
GPath is a path expression language integrated into Groovy which allows to navigate in XML or POJOs. You can perform nested property access in objects.
Method chaining is a technique for invoking multiple method calls in object-oriented programming languages. Each method returns an object (possibly the current object itself), allowing the calls to be chained together in a single statement.
I'm going to use an example with TupleConstructor to assist in the creation of the object.
import groovy.transform.TupleConstructor
#TupleConstructor
class Address {
String name
}
#TupleConstructor
class Person {
String name
Integer age
Address address
}
def person = new Person('John', 25, new Address('Boulevard St'))
Ok, you are right, this access is called GPath:
assert person.address.name == 'Boulevard St'
A getter access could be named method chaining:
assert person.getAddress().getName() == 'Boulevard St'
But what happens if I can do something like this:
person.setName('Louise')
.setAge(40)
.setAddress(new Address('Main St'))
I need to create a fluent API, an method chaining is the way, the idea is to let methods return this rather than void.
#TupleConstructor
class Person {
String name
Integer age
Address address
def setName(name) {
this.name = name
return this
}
def setAge(age) {
this.age = age
return this
}
}
Related
I have a Java code that looks like below code:
for(MyClass myclassObject: input.classes()) {
if(myclassObject.getName().equals("Tom")) {
outputMap.put("output", myclassObject.getAge())
}
}
How do I efficiently write this with Groovy collectmap?
I can do
input.classes().collectEntries["output":it.getAge()] But how do I include the if condition on it?
you could use findAll to keep only items according to condition
and after then apply collectEntries to transform items found
#groovy.transform.ToString
class MyClass{
int age
String name
}
def classes = [
new MyClass(age:11, name:'Tom'),
new MyClass(age:12, name:'Jerry'),
]
classes.findAll{it.getName()=='Tom'}.collectEntries{ [output:it.getAge()] }
Since your resulting map is only retaining one value anyway, you can also just do this:
input.classes().findResult { it.name == 'Tom' ? [output: it.age] : null }
where findResult will return the first item in classes() for which the closure:
{ it.name == 'Tom' ? [output: it.age] : null }
returns a non-null value.
Since you mentioned efficiency in your question: this is more efficient than going through the whole collection using collectEntries or findAll since findResult returns directly on finding the first instance of it.name == 'Tom'.
Which way to go really depends on your requirements.
collectEntries can take a closure as a parameter. You can apply your logic inside the closure and make sure you return the Map Entry when condition passes and return an empty map when condition fails. Therefore;
input.classes().collectEntries { MyClass myClassObject ->
myClassObject.name == 'Tom' ? ['output': myClassObject.getAge()] : [:]
}
However, with your approach there is a caveat. Since you are using the key as output and Map does not allow duplicate keys, you will always end up with the last entry in the map. You have to come up with a better plan if that is not your intention.
Given class Foo with this decidedly poor hashCode() implementation:
class Foo {
String name
public int hashCode() {
0
}
public boolean equals(Object obj) {
if (obj == null) {
return false
}
if (!(obj instanceof Foo)) {
return false
}
Foo foo = (Foo) obj
return this.name.equals(foo.name)
}
}
Why does the following assertion fail?
Foo f1 = new Foo(name: 'Name 1')
Foo f2 = new Foo(name: 'Name 2')
Foo f3 = new Foo(name: 'Name 2')
assert ([f1, f2] - [f3]).size() == 1
The result of the minus() is an empty list. If I switch the hashCode() implementaion toreturn name.hashCode(), the assertion passes. With either implementation, methods like contains() work as expected.
My question is not how to implement a better hashCode(), but why minus() behaves this way.
this would be exactly the behaviour described in the docs for minus:
Create a List composed of the elements of the first list minus every occurrence of elements of the given Collection.
assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]
You remove each element, that is in the second list. In your case remove all f3 from [f1,f2], where all are the same, hence the empty list.
The finer details are in DefaultGroovyMethods.minus and then in NumberAwareComperator, which uses the hashCode. as you have already found, there are open tickets regarding this (https://jira.codehaus.org/browse/GROOVY-7158). So under the eyes, that hashCode is used there, the behaviour is perfectly consistent... should it be used there? maybe not, because there are cases, where it really gets odd (e.g. [[x:0,y:0]]-[[x:1,y:1]]==[]).
The case [f1,f2]-f3 takes another route in code and therefor behaves differently.
For now my best guess would be, that you use minus for immutable types (like above example), where it works quite well. Beside that, rather work with sets.
The java Collections use the implementation of hashCode/equals to determine object equality. Your implementation of hashCode indicates that that f1, f2, and f3 are all "the same". Loosely speaking:
[f1, f2] - [f3]
could be read as
Remove from the list all objects that are the same as f3
so it removes all objects.
You seem to already be aware that this is a terrible way to implement hashCode, so it's really just a case of "garbage in, garbage out".
When using a map of closures to implement an interface in Groovy (as in http://groovy.codehaus.org/Groovy+way+to+implement+interfaces) is there any way to convert the object back to a map after using the as keyword or the asType method to implement the interface?
Based on your use case it would seem that you could just keep a reference to the original Map before converting it into the needed interface.
However, looking at the source code that converts the Map object into the interface (using a Proxy), it looks like you can just re-retrieve the original map by getting the InvocationHandler's delegate.
def i = 1
def m = [ hasNext:{ true }, next:{ i++ } ]
Iterator iter = m as Iterator
def d = java.lang.reflect.Proxy.getInvocationHandler(iter).delegate
assert d.is(m)
Note: This depends on the internals of the Groovy code so use at your own risk:
Interesting question... Short answer, no. Long answer, maybe... Assuming you have something like this:
def i = 1
Iterator iter = [ hasNext:{ true }, next:{ i++ } ] as Iterator
then calling
println iter.take( 3 ).collect()
prints [1,2,3]
Now, you can declare a method to do this:
def mapFromInterface( Object o, Class... clz ) {
// Get a Set of all methods across the array of classes clz
Set methods = clz*.methods.flatten()
// Then, for each of these
methods.collectEntries {
// create a map entry with the name of the method as the key
// and a closure which invokes the method as a value
[ (it.name): { Object... args ->
o.metaClass.pickMethod( it.name, it.parameterTypes ).invoke( o, args )
} ]
}
}
This then allows you to do:
def map = mapFromInterface( iter, Iterator )
And calling:
println map.next()
println map.next()
Will print 4 followed by 5
printing the map with println map gives:
[ remove:ConsoleScript43$_mapFromInterface_closure3_closure4#57752bea,
hasNext:ConsoleScript43$_mapFromInterface_closure3_closure4#4d963c81,
next:ConsoleScript43$_mapFromInterface_closure3_closure4#425e60f2 ]
However, as this is a map, any class which contains multiple methods with the same name and different arguments will fail. I am also not sure how wise it is to do this in the first case...
What is your use-case out of interest?
Groovy supports both default, and named arguments. I just dont see them working together.
I need some classes to support construction using simple non named arguments, and using named arguments like below:
def a1 = new A(2)
def a2 = new A(a: 200, b: "non default")
class A extends SomeBase {
def props
A(a=1, b="str") {
_init(a, b)
}
A(args) {
// use the values in the args map:
_init(args.a, args.b)
props = args
}
private _init(a, b) {
}
}
Is it generally good practice to support both at the same time? Is the above code the only way to it?
The given code will cause some problems. In particular, it'll generate two constructors with a single Object parameter. The first constructor generates bytecode equivalent to:
A() // a,b both default
A(Object) // a set, b default
A(Object, Object) // pass in both
The second generates this:
A(Object) // accepts any object
You can get around this problem by adding some types. Even though groovy has dynamic typing, the type declarations in methods and constructors still matter. For example:
A(int a = 1, String b = "str") { ... }
A(Map args) { ... }
As for good practices, I'd simply use one of the groovy.transform.Canonical or groovy.transform.TupleConstructor annotations. They will provide correct property map and positional parameter constructors automatically. TupleConstructor provides the constructors only, Canonical applies some other best practices with regards to equals, hashCode, and toString.
I am new to groovy and I've been facing some issues understanding the each{} and eachwithindex{} statements in groovy.
Are each and eachWithIndex actually methods? If so what are the arguments that they take?
In the groovy documentation there is this certain example:
def numbers = [ 5, 7, 9, 12 ]
numbers.eachWithIndex{ num, idx -> println "$idx: $num" } //prints each index and number
Well, I see that numbers is an array. What are num and idx in the above statement? What does the -> operator do?
I do know that $idx and $num prints the value, but how is it that idx and num are automatically being associated with the index and contents of the array? What is the logic behind this? Please help.
These are plain methods but they follow quite a specific pattern - they take a Closure as their last argument. A Closure is a piece of functionality that you can pass around and call when applicable.
For example, method eachWithIndex might look like this (roughly):
void eachWithIndex(Closure operation) {
for (int i = 0; this.hasNext(); i++) {
operation(this.next(), i); // Here closure passed as parameter is being called
}
}
This approach allows one to build generic algorithms (like iteration over items) and change the concrete processing logic at runtime by passing different closures.
Regarding the parameters part, as you see in the example above we call the closure (operation) with two parameters - the current element and current index. This means that the eachWithIndex method expects to receive not just any closure but one which would accept these two parameters. From a syntax prospective one defines the parameters during closure definition like this:
{ elem, index ->
// logic
}
So -> is used to separate arguments part of closure definition from its logic. When a closure takes only one argument, its parameter definition can be omitted and then the parameter will be accessible within the closure's scope with the name it (implicit name for the first argument). For example:
[1,2,3].each {
println it
}
It could be rewritten like this:
[1,2,3].each({ elem ->
println elem
})
As you see the Groovy language adds some syntax sugar to make such constructions look prettier.
each and eachWithIndex are, amongst many others, taking so called Closure as an argument. The closure is just a piece of Groovy code wrapped in {} braces. In the code with array:
def numbers = [ 5, 7, 9, 12 ]
numbers.eachWithIndex{ num, idx -> println "$idx: $num" }
there is only one argument (closure, or more precisely: function), please note that in Groovy () braces are sometime optional. num and idx are just an optional aliases for closure (function) arguments, when we need just one argument, this is equivalent (it is implicit name of the first closure argument, very convenient):
def numbers = [ 5, 7, 9, 12 ]
numbers.each {println "$it" }
References:
http://groovy.codehaus.org/Closures
http://en.wikipedia.org/wiki/First-class_function
Normally, if you are using a functional programing language such as Groovy, you would want to avoid using each and eachWithIndex since they encourage you to modify state within the closure or do things that have side effects.
If possible, you may want to do your operations using other groovy collection methods such as .collect or .inject or findResult etc.
However, to use these for your problem, i.e print the list elements with their index, you will need to use the withIndex method on the original collection which will transform the collection to a collection of pairs of [element, index]
For example,
println(['a', 'b', 'c'].withIndex())
EachWithIndex can be used as follows:
package json
import groovy.json.*
import com.eviware.soapui.support.XmlHolder
def project = testRunner.testCase.testSuite.project
def testCase = testRunner.testCase;
def strArray = new String[200]
//Response for a step you want the json from
def response = context.expand('${Offers#Response#$[\'Data\']}').toString()
def json = new JsonSlurper().parseText(response)
//Value you want to compare with in your array
def offername = project.getPropertyValue("Offername")
log.info(offername)
Boolean flagpresent = false
Boolean flagnotpresent = false
strArray = json.Name
def id = 0;
//To find the offername in the array of offers displayed
strArray.eachWithIndex
{
name, index ->
if("${name}" != offername)
{
flagnotpresent= false;
}
else
{
id = "${index}";
flagpresent = true;
log.info("${index}.${name}")
log.info(id)
}
}