I am a Groovy beginner
These are two each calls which both do a similar task but with a different property of s2PublicLifecycleInstance.
How can I write a separate function which does the following, so that I can have only method call to achive the task?
def scheduledStatusArray =[]
def publishedStatusArray =[]
s2PublicLifecycleInstance.each {
if(it.scheduledInMyLearnStatus == "No"){
scheduledStatusArray.add(1)
} else if(it.scheduledInMyLearnStatus == "Yes"){
scheduledStatusArray.add(2)
}else{
scheduledStatusArray.add(3)
}
}
s2PublicLifecycleInstance.each {
if(it.publishedOnTrainingClassesStatus == "No"){
publishedStatusArray.add(1)
}else if(it.publishedOnTrainingClassesStatus == "Yes"){
publishedStatusArray.add(2)
}else{
publishedStatusArray.add(3)
}
}
I want something like this:
def publishedStatusArray = functionCall(s2PublicLifecycleInstance, propertyName)
is it possible in Groovy?
You could use closures and currying:
def checkStatus = { prop,instances ->
def statuses = instances.collect {
switch( it[prop] ) {
case "Yes": 1
break
case "No": 2
break
default: 3
}
}
return statuses
}
def checkScheduledStatus = checkStatus.curry("scheduledInMyLearnStatus")
def checkPublishedStatus = checkStatus.curry("publishedOnTrainingClassesStatus")
def scheduledStatusArray = checkScheduledStatus(s2PublicLifecycleInstance)
def publishedStatusArray = checkPublishedStatus(s2PublicLifecycleInstance)
You can do it this way using a method:
List check( List lifecycle, String param ) {
lifecycle.collect { it ->
switch( it."$param" ) {
case "No":
return 1
case "Yes":
return 2
default:
return 3
}
}
}
def scheduledStatusArray = check( s2PublicLifecycleInstance, 'scheduledInMyLearnStatus' )
def publishedStatusArray = check( s2PublicLifecycleInstance, 'publishedOnTrainingClassesStatus' )
Or, you could do this (which is less code):
List check( List lifecycle, String param ) {
def retvals = [ 'No':1, 'Yes':2 ].withDefault { 3 }
lifecycle.collect { it ->
retvals[ it."$param" ]
}
}
Another alternative would be to use inject with multiple assignment:
def (scheduledStatusArray, publishedStatusArray) = s2PublicLifecycleInstance.inject( [[],[]] ) { lists, it ->
lists[ 0 ] << ( it.scheduledInMyLearnStatus == 'No' ? 1 :
it.scheduledInMyLearnStatus == 'Yes' ? 2 : 3 )
lists[ 1 ] << ( it.publishedOnTrainingClassesStatus == 'No' ? 1 :
it.publishedOnTrainingClassesStatus == 'Yes' ? 2 : 3 )
lists
}
def myMethod(param, arrayToAdd) {
if(param == "No"){
arrayToAdd.add(1)
}else if(param == "Yes"){
arrayToAdd.add(2)
}else{
arrayToAdd.add(3)
}
}
s2PublicLifecycleInstance.each {myMethod(it.scheduledInMyLearnStatus, scheduledStatusArray)}
s2PublicLifecycleInstance.each {myMethod(it.publishedOnTrainingClassesStatus, publishedStatusArray)}
I agree with gasan. I can add, that
def publishedStatusArray = functionCall(s2PublicLifecycleInstance, propertyName)
is possible in groovy. The function:
functionCall(def s2PublicLifecycleInstance, String propertyName){
s2PublicLifecycleInstance."$propertyName"
}
will return the property you want.
Related
I'm a total newbie and I'm looking for some advice.
how to make a condition in Groovy so that if the variable is a string, then one action is performed, and if the sheet is another
and just as it is necessary to do, if the variable is equal to zero, then nothing is transmitted
//aditionalArgs= "test1 = add1 , tets2= add2 "
aditionalArgs = ["test1=arg1", "test2=arg2"]
println(aditionalArgs.class)
def args = ""
if ((aditionalArgs != "class java.lang.String" ) || (aditionalArgs > 0)){
def list = aditionalArgs.replace("--build-arg", "").split(',')
list.each { val->
args += " --build-arg $val"
}
println(args.replace("",""))
}
if (aditionalArgs == "ArrayList" ){
def list = aditionalArgs("--build-arg", "").split('[' , ']')
list.each { val->
args += " --build-arg $val"
}
println(args.replace("",""))
}
else(aditionalArgs.length() > 0){
println "empty aditionalArgs"
}```
if (aditionalArgs instanceof String && aditionalArgs.length() > 0) {
...
} else if (aditionalArgs instanceof List && aditionalArgs.size() > 0) {
...
} else {
println "unsupported arg type '${aditionalArgs?.getClass()}' or value '${aditionalArgs}'"
}
Your code suggests that you rather want to use a switch op:
switch( aditionalArgs ){
case String:
// do stuff with String
break
case List:
// do stuff with (Array)List
break
case Number:
// do something with Number
break
default:
throw new Exception( 'I have no idea' )
}
More on the statement is in the docs
I have a JSON configuration file that I want to read with groovy
this file has "defaults" in case one key would be missing because no specific configuration has been added.
json
{
"presets": {
"default": "preset_default",
"Team1":{
"AppName1":{
"Component1": "preset_team1App1Comp1",
"default" : "preset_team1App1Default"
},
"AppName2":{
"Component1": "preset_team1App2Comp1",
"Component2": "preset_team1App2Comp2"
},
"default" : "preset_team1Default"
},
"Team2":{
"AppName1":{
"Component1": "preset_team2App1Comp1"
}
}
}
}
What would be the most groovy way to search for the value and falling back to the outer most "default" key?
here's how I implemented it but I'm not sure this would work:
if (presets[appTeam])
if (presets[appTeam][appName])
if (presets[appTeam][appName][compName])
this.preset = presets[appTeam][appName][compName]
else
this.preset = presets[appTeam][appName]['default']
else
this.preset = presets[appTeam]['default']
else
this.preset = presets['default']
Thank you in advance
One way would be to use "inject" to walk along your keys, and keep track of the latest default seen... Something like this:
def value(Map presets, String... keys) {
keys.inject([pos: presets, result: presets.default]) { latest, current ->
def node = latest.pos[current]
if (node instanceof Map) {
[pos: node, result: node.default ?: latest.result]
} else if (node instanceof String) {
[pos: node, result: node]
} else if (node == null) {
[pos: node, result: latest.result]
} else {
throw new RuntimeException("No idea what to do with a ${node.class.simpleName}")
}
}.result
}
Then you can do (with the above example)
// Defaults
assert value(presets, 'TeamUnknown', "AppName2", "Component14") == 'preset_default'
assert value(presets, 'Team1', "AppName2", "Component14") == 'preset_team1Default'
// Values
assert value(presets, 'Team1', "AppName2", "Component1") == 'preset_team1App2Comp1'
another way
def value(presets, team, app, compt) {
def defkey = 'default'
return presets.get(team)?.get(app)?.get(compt) ?:
presets.get(team)?.get(app)?.get(defkey) ?:
presets.get(team)?.get(defkey) ?:
presets.get(defkey)
}
assert value(presets, 'TeamUnknown', "AppName2", "Component14") == 'preset_default'
assert value(presets, 'Team1', "AppName2", "Component14") == 'preset_team1Default'
assert value(presets, 'Team1', "AppName2", "Component1") == 'preset_team1App2Comp1'
A simple generic recursion would help:
def input = new groovy.json.JsonSlurper().parseText '''{
"presets": {
"default": "preset_default",
"Team1":{
"AppName1":{
"Component1": "preset_team1App1Comp1",
"default" : "preset_team1App1Default"
},
"AppName2":{
"Component1": "preset_team1App2Comp1",
"Component2": "preset_team1App2Comp2"
},
"default" : "preset_team1Default"
},
"Team2":{
"AppName1":{
"Component1": "preset_team2App1Comp1"
}
}
}
}'''
def findRecursive
findRecursive = { json, List keys, List defaults = [] ->
if( !json || ( json in String ) || !keys ) return json
if( json.default ) defaults << json.default
findRecursive json[ keys.remove( 0 ) ] ?: defaults.last(), keys, defaults
}
assert 'preset_team1App1Comp1' == findRecursive( input.presets, [ 'Team1', 'AppName1', 'Component1' ] )
assert 'preset_team2App1Comp1' == findRecursive( input.presets, [ 'Team2', 'AppName1', 'Component1' ] )
assert 'preset_team1Default' == findRecursive( input.presets, [ 'Team1', 'AppName3', 'Component1' ] )
assert 'preset_default' == findRecursive( input.presets, [ 'Team3' ] )
assert 'preset_default' == findRecursive( input.presets, [ 'Team2', 'AppName2', 'Component1' ] )
I'm writing a test using the Spock framework and I found a strange bavior when testing equality of lists.
When I compare two lists like
sourceList == targetList
and those lists contains Comparable objects of the same type, those objects are tested for equality using its compareTo methods instead of equals.
Is there any simple way how to force Groovy to use equals when testing equality on such lists?
Here is a simple test specification where the test should fail, but it does not.
class Test extends Specification {
def "list test"() {
when:
def listA = [[index: 1, text: "1"] as Bean, [index: 2, text: "2"] as Bean]
def listB = [[index: 1, text: "1"] as Bean, [index: 2, text: "3"] as Bean]
then:
listA == listB
}
class Bean implements Comparable<Bean> {
int index
String text
#Override
public int compareTo(Bean o) {
return index.compareTo(o.index);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + index;
result = prime * result + ((text == null) ? 0 : text.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Bean)) {
return false;
}
Bean other = (Bean) obj;
if (index != other.index) {
return false;
}
if (text == null) {
if (other.text != null) {
return false;
}
} else if (!text.equals(other.text)) {
return false;
}
return true;
}
}
}
Asking for a simple method is subjective. The key to this answer is that, in Groovy, the is() method will check object equality.
Consider this new method on ArrayList. If appropriate, it will zip together the two lists and call is() on each pair of items.
ArrayList.metaClass.myCompare = { listB ->
def result = false
def listA = delegate
if (listB && listA.size() == listB.size()) {
def zipped = [listA, listB].transpose()
result = zipped.inject(true){ ok, pair ->
ok && pair[0].is(pair[1])
}
}
result
}
then:
def beanA = new Bean(index: 1, text: 'a')
def beanA1 = new Bean(index: 1, text: 'a')
def beanB = new Bean(index: 2, text: 'b')
assert [beanA, beanB].myCompare([beanA, beanB])
assert ! [beanA, beanB].myCompare([beanA1, beanB])
assert ! [beanA, beanB].myCompare([beanA])
assert ! [beanA, beanB].myCompare(null)
assert ! [beanA, beanB].myCompare([])
In groovy, "==" is replaced with equals if items are not comparable, or with compareTo if they implement Comparable. I do not know a simple way to force equals, if the collections have no duplicates, you can check the elements of the collection one by one:
def collectionsEqual (Collection<?> collection1, Collection<?> collection2) {
if (collection1.size() != collection2.size()) {
return false
}
for (elem1 in collection1) {
def founded = false;
for (elem2 in collection2) {
if (elem1?.equals (elem2)) {
founded = true
}
}
if (!founded) {
return false
}
}
true
}
but, in https://www.baeldung.com/java-compareto we have:
It is also strongly recommended, though not required, to keep the
compareTo implementation consistent with the equals method
implementation:
x.compareTo(y) == 0 should have the same boolean value as x.equals(y)
This will ensure that we can safely use objects in sorted sets and
sorted maps.
Working on some translation / mapping functionality using Maps/JsonBuilder in Groovy.
Is is possible (without creating extra code outside of the map literal creation) .. to conditionally include/exclude certain key/value pairs ? Some thing along the lines of the following ..
def someConditional = true
def mapResult =
[
"id":123,
"somethingElse":[],
if(someConditional){ return ["onlyIfConditionalTrue":true]}
]
Expected results:
If someConditional if false, only 2 key/value pairs will exist in mapResult.
If someConditional if true, all 3 key/value pairs will exist.
Note that I'm sure it could be done if I create methods / and split things up.. for to keep things concise I would want to keep things inside of the map creation.
You can help yourself with with:
[a:1, b:2].with{
if (false) {
c = 1
}
it
}
With a small helper:
Map newMap(m=[:], Closure c) {
m.with c
m
}
E.g.:
def m = newMap {
a = 1
b = 1
if (true) {
c = 1
}
if (false) {
d = 1
}
}
assert m.a == 1
assert m.b == 1
assert m.c == 1
assert !m.containsKey('d')
Or pass an initial map:
newMap(a:1, b:2) {
if (true) {
c = 1
}
if (false) {
d = 1
}
}
edit
Since Groovy 2.5, there is an alternative for with called tap. It
works like with but does not return the return value from the closure,
but the delegate. So this can be written as:
[a:1, b:2].tap{
if (false) {
c = 1
}
}
You could potentially map all false conditions to a common key (e.g. "/dev/null", "", etc) and then remove that key afterwards as part of a contract. Consider the following:
def condA = true
def condB = false
def condC = false
def mapResult =
[
"id":123,
"somethingElse":[],
(condA ? "condA" : "") : "hello",
(condB ? "condB" : "") : "abc",
(condB ? "condC" : "") : "ijk",
]
// mandatory, arguably reasonable
mapResult.remove("")
assert 3 == mapResult.keySet().size()
assert 123 == mapResult["id"]
assert [] == mapResult["somethingElse"]
assert "hello" == mapResult["condA"]
There is no such syntax, the best you can do is
def someConditional = true
def mapResult = [
"id":123,
"somethingElse":[]
]
if (someConditional) {
mapResult.onlyIfConditionalTrue = true
}
I agree with Donal, without code outside of map creation it is difficult.
At least you would have to implement your own ConditionalMap, it is a little work but perfectly doable.
Each element could have it's own condition like
map["a"] = "A"
map["b"] = "B"
map.put("c","C", true)
map.put("d","D", { myCondition })
etc...
Here an incomplete example (I did only put, get, keySet, values and size to illustrate, and not typed - but you probably don't need types here?), you will probably have to implement few others (isEmpty, containsKey etc...).
class ConditionalMap extends HashMap {
/** Default condition can be a closure */
def defaultCondition = true
/** Put an elemtn with default condition */
def put(key, value) {
super.put(key, new Tuple(defaultCondition, value))
}
/** Put an elemetn with specific condition */
def put(key, value, condition) {
super.put(key, new Tuple(condition, value))
}
/** Get visible element only */
def get(key) {
def tuple = super.get(key)
tuple[0] == true ? tuple[1] : null
}
/** Not part of Map , just to know the real size*/
def int realSize() {
super.keySet().size()
}
/** Includes only the "visible" elements keys */
def Set keySet() {
super.keySet().inject(new HashSet(),
{ result, key
->
def tuple = super.get(key)
if (tuple[0])
result.add(key)
result
})
}
/** Includes only the "visible" elements keys */
def Collection values() {
this.keySet().asCollection().collect({ k -> this[k] })
}
/** Includes only the "visible" elements keys */
def int size() {
this.keySet().size()
}
}
/** default condition that do not accept elements */
def map = new ConditionalMap(defaultCondition: false)
/** condition can be a closure too */
// def map = new ConditionalMap(defaultCondition : {-> true == false })
map["a"] = "A"
map["b"] = "B"
map.put("c","C", true)
map.put("d","D", false)
assert map.size() == 1
assert map.realSize() == 4
println map["a"]
println map["b"]
println map["c"]
println map["d"]
println "size: ${map.size()}"
println "realSize: ${map.realSize()}"
println "keySet: ${map.keySet()}"
println "values: ${map.values()}"
/** end of script */
You can use the spread operator to do this for for both maps and lists:
def t = true
def map = [
a:5,
*:(t ? [b:6] : [:])
]
println(map)
[a:5, b:6]
This works in v3, haven't tried in prior versions.
I'm newbie to groovy/grails.
How to implement thread for this code . Had 2500 urls and this was taking hours of time for checking each url.
so i decided to implement multi-thread for this :
Here is my sample code :
def urls = [
"http://www.wordpress.com",
"http://67.192.103.225/QRA.Public/" ,
"http://www.subaru.com",
"http://baldwinfilter.com/products/start.html"
]
def up = urls.collect { ur ->
try {
def url = new URL(ur)
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
} catch (Exception e) {
return false
}
}
For this code i need to implement multi-threading .
Could any one please suggest me the code.
thanks in advance,
sri.
I would take a look at the Groovy Parallel Systems library. In particular I think that the Parallel collections section would be useful.
Looking at the docs, I believe that collectParallel is a direct drop-in replacement for collect (bearing in mind the obvious caveats about side-effects). The following works fine for me:
def urls = [
"http://www.wordpress.com",
"http://www.subaru.com",
"http://baldwinfilter.com/products/start.html"
]
Parallelizer.doParallel {
def up = urls.collectParallel { ur ->
try {
def url = new URL(ur)
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
} catch (Exception e) {
return false
}
}
println up
}
See the Groovy docs for an example how to use an ExecutorService to do what you want.
You can use this to check the URL in a separate thread.
class URLReader implements Runnable
{
def valid
def url
URLReader( url ) {
this.url = url
}
void run() {
try {
def connection = url.toURL().openConnection()
valid = ( connection.responseCode == 200 ) as Boolean
} catch ( Exception e ) {
println e.message
valid = Boolean.FALSE
}
}
}
def reader = new URLReader( "http://www.google.com" )
new Thread( reader ).start()
while ( reader.valid == null )
{
Thread.sleep( 500 )
}
println "valid: ${reader.valid}"
Notes: The valid attribute will be either null, Boolean.TRUE or Boolean.FALSE. You'll need to wait for a while to give all the threads a chance to open the connection. Depending on the number of URLs you're checking you will eventually hit a limit of the number of threads / connections you can realistically handle, so should check URLs in batches of the appropriate size.
I think this way is very simple to achieve.
import java.util.concurrent.*
//Thread number
THREADS = 100
pool = Executors.newFixedThreadPool(THREADS)
defer = { c -> pool.submit(c as Callable) }
def urls = [
"http://www.wordpress.com",
"http://www.subaru.com",
]
def getUrl = { url ->
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
}
def up = urls.collect { ur ->
try {
def url = new URL(ur)
defer{ getUrl(url) }.get()
} catch (Exception e) {
return false
}
}
println up
pool.shutdown()
This is how I implemented:
class ValidateLinks extends Thread{
def valid
def url
ValidateLinks( url ) {
this.url = url
}
void run() {
try {
def connection = url.toURL().openConnection()
connection.setConnectTimeout(5000)
valid = ( connection.responseCode == 200 ) as Boolean
} catch ( Exception e ) {
println url + "-" + e.message
valid = Boolean.FALSE
}
}
}
def threads = [];
urls.each { ur ->
def reader = new ValidateLinks(ur.site_url)
reader.start()
threads.add(reader);
}
while (threads.size() > 0) {
for(int i =0; i < threads.size();i++) {
def tr = threads.get(i);
if (!tr.isAlive()) {
println "URL : " + tr.url + "Valid " + tr.valid
threads.remove(i);
i--;
}
}
}