开发者

recursion in groovy (grails)

开发者 https://www.devze.com 2023-01-05 01:02 出处:网络
I am trying to use recursion in groovy to traverse a tree relationship. The below code runs one cycle, uptochildNodes && recurClosure(childNodes ) , but doesn\'t call the closure recurClosure

I am trying to use recursion in groovy to traverse a tree relationship. The below code runs one cycle, upto childNodes && recurClosure(childNodes ) , but doesn't call the closure recurClosure again. At that instant childNodes had two objects (array list) same type as root.

In the code, recurClosure is defined and calls with a list of objects (root). It then iterates through each element and fines the child nodes (uses grails dsl for this).If t开发者_如何学运维he childNodes is not null, it recursively calls the parent method.

Should I break it up, or what is wrong?

def parentval 
def root = Domain.list()

def recurClosure
recurClosure = {inroot ->
  inroot.each {
    returnList << it
    parentval = it
    childNodes = Domain.withCriteria {
      eq('parent', parentval )
    }
  }
  childNodes && recurClosure(childNodes )
}(root)

return returnList

}

thanks in advance.

Update: The following exception is noted

    ERROR [2010-06-24 08:20:04,742] [groovy.grails.web.errors.GrailsExceptionResolver] Cannot invoke method call() on null object
java.lang.NullPointerException: Cannot invoke method call() on null object
    at com.bsr.test.DomainService$_closure2_closure7.doCall(com.bsr.test.DomainService:68)
    at com.bsr.test.DomainService$_closure2.doCall(com.bsr.test.DomainService:58)
    at com.bsr.test.DomainController$_closure3.doCall(DomainController.groovy:45)
    at com.bsr.test.DomainController$_closure3.doCall(DomainController.groovy)
    at org.apache.shiro.web.servlet.ShiroFilter.executeChain(ShiroFilter.java:687)
    at org.apache.shiro.web.servlet.ShiroFilter.doFilterInternal(ShiroFilter.java:616)
    at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:81)
    at java.lang.Thread.run(Thread.java:619)

Update 2: Now trying Daniel's suggestion.

{ inroot ->
    inroot.each {
        returnList << it
        parentval = it
        childNodes = Domain.withCriteria {
            eq('parent', parentval )
        }
           if(childNodes)
           call(childNodes)
    }
       /*if(childNodes)
        call(childNodes)*/

}(root)

In the above implementation, root is an arraylist, The inner closure takes each element out of it and recursively calls the anonymous closure. When I moved the 'call' inside the each closure, it doesn't call the outer anonymous closure, but the inroot.each {} itself. So, I get an error

ERROR [2010-06-24 08:47:46,438] [groovy.grails.web.errors.GrailsExceptionResolver] instance not of expected entity type: java.util.ArrayList is not a: com.bsr.test.Domain

I see a blog post about how to name the closure through 'this' > I'll update my finding.. thanks

Update 3: The way to call the outer closure is owner.call(childNodes)


The problem is, that by

recurClosure = {
    [...]
}(root)

you don't assign the closure to recurClosure, but rather the return value of its invocation! Thus, of course, you can't call the closure via recurClosure()...

Two possible solutions:

First define the closure, and then call it separately, as air_blob suggested:

def recurClosure = {
    [...]
}
recurClosure(root)

Use the implicit call() function for recursion. This way you can even work with an anonymous closure. IMHO a very nice way to implement recursion in Groovy:

{ inroot ->
    inroot.each {
        returnList << it
        parentval = it
        childNodes = Domain.withCriteria {
            eq('parent', parentval )
        }
    }
    if(childNodes)
        call(childNodes)
}(root)

Two more comments on your code:

  1. You may want to declare returnList: def returnList = []
  2. While childNodes && recurClosure(childNodes ) may do what you want, it's much more readable to sacrifice one more char and spell out the if.. ;-)
  3. Don't you want to recursively call your closure inside the each?

Another (higher-level) remark on your code: If the parents and their children are of the same type (Domain), won't Domain.list() actually return all children, too? Is there really a need for traversing the tree manually?


Do you get any exceptions? Have you tried invoking it separately like this:

def recurClosure
recurClosure = {inroot ->
  [... stuff ...]
}

recurClosure(root)

What exactly do you want to do in this line:

childNodes && recurClosure(childNodes )
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号