= GEP-7: JSON Support :icons: font .Metadata **** [horizontal,options="compact"] *Number*:: GEP-7 *Title*:: JSON Support *Version*:: 4 *Type*:: Feature *Status*:: Final *Comment*:: Delivered in Groovy 1.8 *Leader*:: Guillaume Laforge *Contributors*:: Andres Almiray *Created*:: 2010-10-25 *Last modification* :: 2018-10-12 **** == Abstract: JSON Support Provide a builder/slurper combination for handling data in JSON format in a similar fashion as it's already done for XML. == Rationale JSON has become ubiquitous to the web. RESTful services exchange data in both POX (Plain Old XML) and JSON formats. Groovy has excellent support for producing/consuming XML with MarkupBuilder, XmlSlurper and XmlParser but lacks this kind support for JSON. This GEP strives to remedy the situation, by providing a compatible builder approach. === Producing JSON The following builder syntax is proposed ``` def builder = new groovy.json.JsonBuilder() def root = builder.people { person { firstName 'Guillame' lastName 'Laforge' // Maps are valid values for objects too address( city: 'Paris', country: 'France', zip: 12345, ) married true conferences 'JavaOne', 'Gr8conf' } } // creates a data structure made of maps (Json object) and lists (Json array) assert root instanceof Map println builder.toString() // prints (without formatting) {"people": { "person": { "firstName": "Guillaume", "lastName": "Laforge", "address": { "city": "Paris", "country": "France", "zip": 12345 }, "married": true, "conferences": [ "JavaOne", "Gr8conf" ] } } ``` Valid node values are: `Number`, `String`, `GString`, `Boolean`, `Map`, `List`. `null` is reserved for object references. Arrays can not be null, but they can be empty. Anything else results in an IAE (or a more specialized exception) being thrown. === Special cases There is a special case to be considered: when the top node results in an anonymous object or array. or objects a call() method on the builder is needed which takes a map as argument, for arrays call() takes a vararg of values. Here are some examples: ``` builder.foo "foo" // produces {foo: "foo"} ``` ``` builder([{ foo 'foo' }]) // produces [{"foo": "foo"}] ``` ``` builder([[ foo: 'foo' ]]) // produces, same as above [{"foo": "foo"}] ``` ``` builder { elem 1, 2, 3 } // produces { "elem": [1, 2, 3] } ``` When a method is called on the builder without arguments, and empty JSON object is associated with the key: ``` builder.element() // produces { "element": {} } ``` You can also pass a map and a closure argument: ``` builder.person(name: "Guillaume", age: 33) { town "Paris" } // produces {"name": "Guillaume", "age": 33, "town": "Paris} ``` Calls like the following, with a map and a value, don't have any meaningful representation in JSON (unlike in XML), and triggers a JsonException: ``` shouldFail(JsonException) { builder.elem(a: 1, b: 2, "some text value") } ``` In case of overlapping keys in the map and the closure, the closure wins – a visual clue for this rule is that the closure appears "after" the map key/value pairs. Consuming JSON The proposal is for the creation of a JsonSlurper class that can read JSON from a string (in a non-streaming fashion) and produce a hierarchy of maps and lists representing the JSON objects and arrays respectively. ``` String json = '{"person": {"firstName": "Guillaume", "lastName": "Laforge", "conferences": ["JavaOne", "Gr8conf"]}}' def root = new JsonSlurper().parseText(json) assert root instanceof Map assert root.person.conferences instanceof List assert root.person.firstName == 'Guillaume' assert root.person.conferences[1] == 'Gr8conf' ``` JsonSlurper's API should mirror closely what XmlParser/XmlSlurper offers in terms of its parse* method variants. == References and useful links JSON Spec and Java implementations * http://json.org/[json.org] * http://tools.ietf.org/html/rfc4627[RFC-4627] * http://json-lib.sourceforge.net/[json-lib] === Mailing-list discussions * https://marc.info/?l=groovy-dev&m=129623197505984&w=2[groovy-dev: Built-in JSON support in 1.8] === JIRA issues * https://issues.apache.org/jira/browse/GROOVY-4644[GROOVY-4644: JSON support: provide a parser and a builder for JSON content] == Update history 3 (2011-02-02):: Version as extracted from Codehaus wiki 4 (2018-10-16):: Numerous minor tweaks

GEP-7