Edit: This fix has been checked into the evolving 1.6 version, and the developers are discussing if it will be in the final 1.5.x release.
Let’s start with the punchline:
def x = [ [a:1, b:2, c:3] ] def y = x.flatten() assertEquals([1, 2, 3], y)
So, flatten, whose JavaDoc says that it flattens containing collections, also extracts the views from maps and flattens those. This is odd. It wouldn’t have been a big deal, except that I regularly use maps as “pseudobeans”.
Consider this case:
def fetchX(inBean) { inBean.props.x(SOME_CONST) }
If I were to unit test that, I’d generally do something like this:
def arg = null def inBean = [ props : [ x : { it -> arg = it; 5 } ] ] def out = fetchX(inBean) assertEquals(5, out) assertEquals(SOME_CONST, arg)
What I’m doing is mocking out the property access by leveraging Groovy’s dot-accessor for maps. Since property accessors for beans and the dot-accessor for maps are the same syntax, I can use them interchangeably. I’m also faking a method by adding a closure to a map, since calling a closure from a map via the dot accessor looks exactly like a method call. And, just for fun, I captured the method argument via a closure. There’s more on this stunt here.
Unfortunately, the difference between using JavaBeans and maps becomes readily apparent if you use #flatten, because it mangles maps. This is sad, and resulted in the hackiness of re-writing list#flatten in my application.
Other issues with list#flatten at the moment:
- It doesn’t flatten arrays.
- It causes a stack overflow if a list contains itself.
I submitted a patch to fix the map issue, and someone else enhanced the patch to handle arrays. I’m going to update the stack overflow issue later today, when I’m done working.
Here are two tickets where you can learn more:
GROOVY-2903
GROOVY-2904
Related posts:
Pingback: Enfranchised Mind » Twitter and Blogging