Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy differences between 'as' and casting

Tags:

grails

groovy

Using Grails, this:

[[a:1]] as grails.converters.JSON 

returns a different thing than

(grails.converters.JSON)[[a:1]]

but both works more or less as expected, so I assume that both calls are handled by the JSON class, but by different methods (or parameters).

I know the as calls the asType method, but what is being called when the casting is invoked?

EDIT:

I initially thought it wouldn't be relevant, but for completeness, the 'as' returns

[{"a":1}]

while the casting returns

{"a":1}

If the list contains more than one item, both returns the same. Also, in both cases, both methods return an object whose class is grails.converters.JSON.

If it adds any value, I tried with Grails 2.2.4.

like image 913
Deigote Avatar asked Oct 21 '13 12:10

Deigote


2 Answers

Here is how it works:

  • grails.converters.JSON is part of grails' converters plugin.
  • The turning point, it does use Groovy's asType effectively in ConvertersApi which makes sure that the converter (in this case JSON) in instantiated based on the application context.
  • And a target is set on the converter. Target being the delegate (in your example the list with one element [[a:1]])
  • The only difference you see when you typecast the collection manually is that the target is not set in the converter. Therefore, a missing link during conversion.
  • Based on the converter's basics, it tries to convert the collection to a JSONObject or a JSONArray by its own without bothering what the target is.

Here is how it can be tested:

@Grab('org.json:json:20090211')
import grails.converters.JSON
import org.json.*

println([[a:1]] as JSON) //Gives [{"a":1}], works as expected
println((JSON)[[a:1]]) //Gives {"a":1} since target on converter is not set

//Manual typecast + set target
def op = (JSON)[[a:1]] //or op = new JSON([[a:1]])
op.setTarget([[a:1]])

println op //[{"a":1}] expected result because target is set

//Basic typecast to JSONObject
println((JSONObject)[[a:1]]) //{"a":1}

//With manual casting it behaves as if casted with JSONObject or JSONArray
assert ((JSON)[[a:1]]).toString() == ((JSONObject)[[a:1]]).toString()
assert ((JSON)[[a:1],[b:2]]).toString() == ((JSONArray)[[a:1],[b:2]]).toString()

//Extra massaging done by JSON converter on object
//which is not available when manually casted
JSONObject.valueToString([[a:1]]) //[{"a":1}]
like image 130
dmahapatro Avatar answered Oct 31 '22 08:10

dmahapatro


[[a:1]] as grails.converters.JSON 

This is handle by grails-converters plugin (i.e. ConvertersGrailsPlugin.groovy)whose aims to give you the ability to convert your domain objects, maps and lists to JSON or XML very quickly, to ease development for AJAX based applications. The plugin leverages the the groovy "as" operator and extends the render method in grails controllers to directly send the result to the output stream. It also adds the Grails Codecs mechanism for XML and JSON. Where as:

(grails.converters.JSON)[[a:1]]

is a doing type casting to JSON object. I think it will help you to understand these are two different aspect and not handle by JSON class. :)

like image 33
Yogesh Avatar answered Oct 31 '22 10:10

Yogesh