I’m running into some confusing behaviour from LinkedHashMap in
grails 2.0.3. Running the following script in grails console:
def m = ["smart-1":[stuff:'asdf']]
println m.getClass()
def p = [id:1]
println m."smart-$p.id"
println m["smart-$p.id"]
println m.get("smart-$p.id")
println m.'smart-1'
println m['smart-1']
println m.get('smart-1')
gives the output:
class java.util.LinkedHashMap
[stuff:asdf]
[stuff:asdf]
null
[stuff:asdf]
[stuff:asdf]
[stuff:asdf]
In an integration test, I’m seeing the opposite behaviour – I can only
get the content of the HashMap using m.get(GStringImpl) (as opposed
m.get(String)).
Is this behaviour expected or known?
First: don’t use GStrings in your hashmap keys. Ever. You will almost always have an issue retrieving the item, because a GString is not a String (red box on that page), and does not have the same hash value. Instead, use one of these options:
This ensures that you will always get the result when using a String. (So, for lookups, always use a String, too.)
I’m not 100% sure why you are seeing the odd behavior, but I have a solid guess. The
get()method is a Java method, while the array-style (and probably property-style) lookup is implemented usinggetAt(), which is a Groovy (GDK) method. My guess is that the Groovy method is aware of GStrings, and silently handles the conversion to make sure you don’t get tripped up.The simplest solution is to always use
getAt(), notget:Which works fine.
The better solution is to ensure that you are using Strings when looking up values, like so:
Which also works. I like this method better, because when calling the method directly, it’s clearer that your key is a String. I’d still use the normal GString when using the array-style or property-style accessors, because that’s standard Groovy syntax.
This is most likely because your key in your hashmap is staying a GString.
If a GString does not have any variables, the Groovy compiler silently converts it to a String literal (better performance), which is why the above example is actually using a String as the key, but the lookup is using a GString.
e.g.
A final thought: As long as you are in groovy, don’t use
get(), since Groovy provides the much cleaner[]and property syntaxes.