Anthony
Anthony

Reputation: 36008

Groovy Closure explanation

I'm familiar with normal groovy closures like these

def printSum = {a,b ->
   println a+b
}

printSum(5,7) // 12

However, I came across code from SpringWS plugin that I have a hard time understanding:

def withEndpointRequest = { url, payload ->
    def writer = new StringWriter()
    def request = new MarkupBuilder(writer)
    payload.delegate = request
    payload.call()
    def webServiceTemplate = new WebServiceTemplate()

    def response = webServiceTemplate.sendToEndpoint(url, writer.toString())
    new XmlSlurper().parseText(response)
}

I understand that above is a closure.

It is being used like this:

    def namespace = "http://www.myveryimportantcompany.com/hr/schemas"
    def serviceURL = "http://localhost:8080/myapp/services"
    def response = withEndpointRequest(serviceURL) {
        HolidayRequest(xmlns: namespace) {
            Holiday {
                StartDate("2006-07-03")
                EndDate("2006-07-07")
            }
            Employee {
                Number("42")
                FirstName("Russ")
                LastName("Miles")
            }
        }
    }

if serviceURL is being passed in then where is the payload?

Can someone please explain this snippet in some detail?

Upvotes: 5

Views: 557

Answers (2)

Guillaume Barré
Guillaume Barré

Reputation: 4228

The following snipet, posted here, gives an overview of several options used to pass a closure into a method.

Method with two arguments. Last argument is a closure.

def work(input, cl) {
    cl(input)
}

Define a closure.

def assertJava = {
    it == 'Java'
}

Ways to pass the closure to the method

work('Java', assertJava)

work 'Java', assertJava  // No parenthesis.

work('Groovy', {
    assert it == 'Groovy'
})  // Anonymous closure as argument.

work('Groovy') {
    assert it == 'Groovy'
}  // Last argument is closure and can be outside parenthesis. 

work('Groovy')
{
     assert it == 'Groovy'
}  // Opening bracket on new line. If we want a code block (e.g. static initializer) instead of closure we must use ; to separate code.


work 'Groovy', {
    assert it == 'Groovy'
}  // Pay attention, no parenthesis, so comma is needed again!


// Does not work:
//
// Comma between argument list needed:
// work 'Groovy' {
//     assert it == 'Groovy'
// }

Upvotes: 0

dmahapatro
dmahapatro

Reputation: 50275

In the above implementation, withEndpointRequest is a closure which takes two parameters.

withEndpointRequest(String serviceUrl, Closure payload).

When you are using withEndpointRequest from your client, you are actually doing

    def namespace = "http://www.myveryimportantcompany.com/hr/schemas"
    def serviceURL = "http://localhost:8080/myapp/services"
    def payload = {
         HolidayRequest(xmlns: namespace) {
            Holiday {
                StartDate("2006-07-03")
                EndDate("2006-07-07")
            }
            Employee {
                Number("42")
                FirstName("Russ")
                LastName("Miles")
            }
        }
    }
    def response = withEndpointRequest(serviceURL, payload) 

The above was made groovier by declaring the closure inline with withEndpointRequest. The above can also be written as

def response = withEndpointRequest(serviceURL, {
        //payload goes here as an inline closure as the second parameter
        HolidayRequest(xmlns: namespace) {
            Holiday {
                StartDate("2006-07-03")
                EndDate("2006-07-07")
            }
            Employee {
                Number("42")
                FirstName("Russ")
                LastName("Miles")
            }
        }
    })

which is less verbose. Finally, it can be streamlined and made more groovier by writing as

def response = withEndpointRequest(serviceURL) {
        HolidayRequest(xmlns: namespace) {
            Holiday {
                StartDate("2006-07-03")
                EndDate("2006-07-07")
            }
            Employee {
                Number("42")
                FirstName("Russ")
                LastName("Miles")
            }
        }
    }

One point to note here is that the Closure payload is the last parameter.

Now, note that the closure (payload) is not invoked until payload.call() is invoked as mentioned in your question inside SpringWS plugin.

Have a look at Closures as Method Arguments.

I hope I was able to convey what you wanted to understand. :)

Upvotes: 4

Related Questions