Since Groovy 1.8 we can check if a Map is equal to another Map if the keys and values are the same. Very convenient in tests for example.

def someMap = [age: 34, name: "Ted"]
assert someMap == [name: "Ted", age: 34] 

Today I kept staring at a failure, while testing some x and y graph data points returned by a Grails controller, where two Maps were somehow not equal according to Spock, while even the assertion’s output looked ‘equal’.



and: "series are present"
def series = response.json
series.size() == 2

and: "realized series is correct"
and: "predicted series is correct"
def predictedSeries = series[1]
predictedSeries.values.size() == 2
predictedSeries.values[0] == [y:null, x:'Mar']
predictedSeries.values[1] == [y:121, x:'Apr']

resulted in:

Condition not satisfied:
predictedSeries.values[0] == [y:null, x:'Mar']
|               |     |   |
|               |     |   false
|               |     [y:null, x:Mar]
|               [[y:null, x:Mar], [y:121, x:Apr]]
[values:[[y:null, x:Mar], [y:121, x:Apr]]]

Why isn’t [y:null, x:Mar] equal to [y:null, x:Mar]?

After having checked explicitly with

predictedSeries.values[0].x == 'Mar'
predictedSeries.values[0].y == null // <- better be null!

I remembered again I was dealing with JSON data in Grails, which uses the Null Object pattern. Keeps biting me every now and then 🙂

Condition not satisfied:
predictedSeries.values[0].y == null
|               |     |   | |
|               |     |   | false
|               |     |   null (org.codehaus.groovy.grails.web.json.JSONObject$Null)
|               |     [y:null, x:Mar]
|               [[y:null, x:Mar], [y:121, x:Apr]]
[values:[[y:null, x:Mar], [y:121, x:Apr]]]

Grails JSONObject null

It’s a JSONObject$Null instance. It exists because it’s equivalent to the value that JavaScript calls null, whilst Java’s null is equivalent to the value that JavaScript calls undefined.

There are some long time posts already describing this behaviour that JSONObject.NULL was not equal to null

JSONObject.NULL.equals(null) // true
JSONObject.NULL == null // false!!

and some meta-class changes you could do were suggested at the time. Seems reported GRAILS-7739 (Wrong == and asBoolean behavior for JSONObject.Null) says it’s been fixed a few years back in Grails 2.2.

Atleast something has been fixed. Although you still can not do JSONObject.NULL == null, you can change the assertion to using Groovy Truth since !JSONObject.NULL does work.

// or predictedSeries.values[0] == [y: JSONObject.NULL, x:'Mar'] if you like

And of course I should remember null in (console) output is always a String representation leading to “null” – such as JSONObject.NULL‘s toString() returns.