DJOodle
DJOodle

Reputation: 323

Groovy map with an array as a key returns null when given a key equivalent to one I know exists

Riddle me this,

In my code, I am using a map to store all the methods of an object which have my annotation. Because of the way I wanted to use the map, I'm storing the java.reflection.Method object as the value, and the key is an array list containing the method name as a String and the parameter types as a Class[]

to create the map my code does the following:

def map = [:]
Foo.metaClass.methods*.cachedMethod.each { 
    if(it.isAnnotationPresent(Test.class)) { 
        map << [([it.name, it.parameterTypes]):it] 
    } 
}

This successfully returns me a map containing something similar to this:

[[exampleMethod, [class java.lang.String, class java.lang.String]]:public java.util.List Foo.exampleMethod(java.lang.String,java.lang.String)]

I can examine the key and print the classes and know that its made up of an ArrayList where the first element is a String and the second is a Class[] containing two Strings

Whilst testing this code, I built an Array list which is equivalent to a key i knoiw exists in the map:

def tstKey = ["exampleMethod" as String, [String.class, String.class]]

And I know this is equivalent to a current key with an assert:

assert tstKey == curKey

Which passes fine... However when I try to access the element by tstKey it returns null. Yet accessing the element by curKey returns the element.

This has left me scratching my head a little. If they are equivalent arrays, why can't I return the element using the built tstKey?

SIDENOTE: I tried using getParamTypes() on the CachedMethod instead of getParameterTypes on the actual method, however it returned null despite getParamsCount returning 2, any ideas why that would be?

Upvotes: 2

Views: 2101

Answers (1)

Dror Bereznitsky
Dror Bereznitsky

Reputation: 20386

The core reason is that it.parameterTypes returns a Java Object array. So, first of all you will need to change the following:

def tstKey = ["exampleMethod" as String, [String.class, String.class] as Class<?>[]]

Now the real issue is that the ArrayList hash code is used when getting the values out of the map. The ArrayList hash code is based on the hash codes of its elements and one of them is the Java array. The Java array hash code is based on the object reference as done in Object, so no 2 arrays will have the same hash code.
If you'll print the hash code of your two keys, you will see that they are not the same.

Upvotes: 4

Related Questions