Reflections on Maps and Lists
Andres Almiray June 1st, 2007
While testing the new Groovy features of Json-lib I discovered some things that made me reflect back on some of the Groovy magic that we have come to love, I suspect that most of the issues have to do with JSONObject and JSONArray now implementing Map and List.
When coding the leftShift operator for JSONObject I decided to process Maps and Lists only, if the parameter was a list (of size >= 2) I’ll just grab the first element and treat it like a key, so it fell very natural to write something like:
- json.element( list.shift, list )
… And obviously it didn’t work because Lists do not have a shift method! (talking about a serious case of Perl memories), the ‘workaround’ is not a problem as shift is in reality a call to remove(0) at the very least. I wonder if we need this syntactic sugar in the GDK…
JSONObject and JSONArray also implement java.util.Comparable, which is the requirement for the comparison operators to work on your classes, although all of them seem to work fine with JSONObject, it is not the case for JSONArray as the following code cases a ScriptException:
- def array1 = JSONArray.formObject([1,2,3])
- def array2 = JSONArray.fromObject([1,2,3,4])
- assert array1 < array2
This is where I think that the way Groovy handles Lists is preventing JSONArray to handle the operator (I have yet to confirm this) but adding log entries to compareTo shows that the method is not called, even if a custom MetaClass is in place (adding logging to invokeMethod). Which takes me to the third issue I found, which is the toString() method. Both JSONarray and JSONObject provide their own implementation but when printed to the console the output appears to be handled by Map’s and List’s toString method:
- def object = new JSONObject().element(“key”,1)
- def array = JSONArray.fromObject([object])
- println object // [”key,1] instead of {”key”:1}
- println array // [[”key”,1]] instead of [{”key”:1}]
You may think that the problem lies only on JSONObject, but if a JSONFunction is stored as an element on an array, its string representation will be surrounded by double quotes (List.toString() in action) instead of being printed as is (JSONarray.toString() in action). Calls to toString() are not registered by my JSONObjectMetaClass.invokeMethod, that’s why I think someone else intercepted the call first =(
I’ll keep looking for alternatives for my compareTo() and toString() problems, luckily I have a copy of GINA by my side.
Keep on Groovying!
Tags: Andres Almiray
About