Creating Map using withDefault causing null when putting element
groovy
Solution
The problem isn't just about the cast. It also has to do with the declared type. The problem can be simplified to something like this:
def map1 = [:].withDefault { 0 }
TreeMap map2 = map1
When that is executed `map1` is an instance of `groovy.lang.MapWithDefault` and `map2` is an instance of `java.util.TreeMap`. They are 2 separate objects on the heap, not just 2 references pointing to the same object. `map2` will not have any default behavior associated with it. It is as if you had done this:
def map1 = [:].withDefault { 0 }
TreeMap map2 = new TreeMap(map1)
That is what is happening with your code. The cast and the generics just makes it less clear with your code.
This:
TreeMap<String, List<Data>> myData = (TreeMap<String, List<Data>>) [:].withDefault { [] }
Can be broken down to this:
def tmpMap = [:].withDefault { [] }
TreeMap<String, List<Data>> myData = (TreeMap<String, List<Data>>)tmpMap
I hope that helps.
EDIT:
Another way to see the same thing happening is to do something like this:
Set names = new HashSet()
ArrayList namesList = names
When the second line executes a new ArrayList is created as if you had done `ArrayList namesList = new ArrayList(names)`. That looks different than what you have in your code, but the same sort of thing is happening. You have a reference with a static type associated with it and are pointing that reference at an object of a different type and Groovy is creating an instance of your declared type. In this simple example above, that declared type is `ArrayList`. In your example that declared type is `TreeMap<String, List<Data>>`.
Problem
I'm trying to use the Groovy way of creating a `TreeMap<String, List<Data>>` with default values so I easily add data to a new list if the key isn't already present. `TreeMap<String, List<Data>> myData = (TreeMap<String, List<Data>>) [:].withDefault { [] }` As you can see, I have the requirement to use a `TreeMap` and `withDefault` only returns a `Map` instance, so I need to cast. When I attempt to add a new list to the map, `myData[newKey].add(newData)` `myData[newKey]` is `null`. However, if I change my `Map` initilization to remove the `TreeMap` cast (and change the type to just `Map` instead of `TreeMap`), `myData[newKey].add(newData)` works as expected. What's the reasoning for this? Can I not use `withDefault` if I cast the map?