Al-Punk
Al-Punk

Reputation: 3669

If statements in Groovy Closures

I am attempting to write a mini recursive closure to solve a parent children iteration. At a certain moment I need check if other children exists before I recursively call the closure. I do the check with an IF but for some reason the if returns always true.

Updating the code with the objects that are included

Have an Json object which has the structure Parent Children (referred as jsonArray in the code below)

   [
    {
        "id": "1",
        "name": "No Children" //And yet the if condition is true -> element.children
    },
    {
        "id": "2",
        "name": "Does not like Children either"
    },
    {
        "id": "123",
        "name": "Some Parent Element",
        "children": [
            {
                "id": "123123",
                "name": "NameWhatever"
            },
            {
                "id": "123123123",
                "name": "Element with Additional Children",
                "children": [
                    {
                        "id": "123123123",
                        "name": "WhateverChildName"
                    },
                    {
                        "id": "12112",
                        "name": "NameToMap"
                    }
                ]
            }
        ]
    }
]

There is also an ArrayList object which has no IDs and need to retrieve them from the iteration in the jsonArray, This is referred to as elementsToGetID which I am oversimplifying:

["count": 2741,"value": "NameToMap" ], ["count": 133,"value": "OtherName" ]

Thetwo for loops have been written time ago, and I am trying to write the recursive closure to go deeper into the children

for(int i=0; i<elementsToGetID.size(); i++){
    for(int j=0; j<jsonArray.size(); j++){

        { element ->
            if(element.name == elementsToGetID[i].value){
                elementsToGetID[i]["id"] = element.id
            }
            if (element.children) {
                element.children.each {inst ->
                    log.info "Element to continue function " +inst
                    call(inst) //This call fails
                }
            }
        }(jsonArray[j])

    }
}

Upvotes: 3

Views: 8555

Answers (2)

tim_yates
tim_yates

Reputation: 171194

You can replace the multiple for loops in dmahapatro's correct answer:

for(int i=0; i < elementsToGetID.size(); i++){
    for(int j=0; j < jsonArray.size(); j++){
        def closure //defined locally

        closure = { element ->
            if(element.name == elementsToGetID[i].value){
                elementsToGetID[i]["id"] = element.id
            }
            if (element.children) {
                element.children.each {inst ->
                    closure(inst) //This call does not fail anymore
                }
            }
        }

        closure(jsonArray[j])
    }
}

with this, to get the same result:

jsonArray.each { a ->
    elementsToGetID.find { a.name == it.value }?.id = a.id
    if( a.children ) {
        { -> a.children.each( owner ) }()
    }
}

Upvotes: 3

dmahapatro
dmahapatro

Reputation: 50285

This is the benefit. It works. :)

Reason
For recursion, a closure has to understand itself that it is defined before it is invoked.

def json = '''
[
    {
        "id": "1",
        "name": "No Children"
    },
    {
        "id": "2",
        "name": "Does not like Children either"
    },
    {
        "id": "123",
        "name": "Some Parent Element",
        "children": [
            {
                "id": "123123",
                "name": "NameWhatever"
            },
            {
                "id": "123123123",
                "name": "Element with Additional Children",
                "children": [
                    {
                        "id": "123123123",
                        "name": "WhateverChildName"
                    },
                    {
                        "id": "12112",
                        "name": "NameToMap"
                    }
                ]
            }
        ]
    }
]
'''

def jsonArray = new groovy.json.JsonSlurper().parseText(json)
def elementsToGetID = [["count": 2741,"value": "NameToMap" ], 
                       ["count": 133,"value": "OtherName" ]]

//can be defined here as well
//def closure

for(int i=0; i < elementsToGetID.size(); i++){
    for(int j=0; j < jsonArray.size(); j++){
        def closure //defined locally

        closure = { element ->
            if(element.name == elementsToGetID[i].value){
                elementsToGetID[i]["id"] = element.id
            }
            if (element.children) {
                element.children.each {inst ->
                    closure(inst) //This call does not fail anymore
                }
            }
        }

        closure(jsonArray[j])
    }
}

assert elementsToGetID == [[count:2741, value:'NameToMap', id:'12112'], 
                           [count:133, value:'OtherName']]

Upvotes: 2

Related Questions