GEP-7


元数据
编号

GEP-7

标题

JSON 支持

版本

4

类型

功能

状态

最终版

评论

在 Groovy 1.8 中交付

负责人

Guillaume Laforge

贡献者

Andres Almiray

创建日期

2010-10-25

最后修改时间 

2018-10-12

摘要:JSON 支持

提供一个构建器/解析器组合,用于以类似于 XML 的方式处理 JSON 格式的数据。

理由

JSON 已成为 Web 上无处不在的格式。RESTful 服务在 POX(普通旧 XML)和 JSON 格式之间交换数据。Groovy 在使用 MarkupBuilder、XmlSlurper 和 XmlParser 生成/使用 XML 方面有出色的支持,但缺乏对 JSON 的这种支持。此 GEP 致力于通过提供兼容的构建器方法来弥补这一不足。

生成 JSON

建议使用以下构建器语法

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"
        ]
    }
}

有效节点值包括:NumberStringGStringBooleanMapListnull 用于对象引用。数组不能为 null,但可以为空。任何其他值都会导致抛出 IAE(或更专业的异常)。

特殊情况

需要考虑一种特殊情况:当顶层节点导致匿名对象或数组时,或者对象在构建器上调用 call() 方法时,该方法需要一个 map 作为参数,对于数组,call() 需要一个包含值的 vararg。以下是一些示例

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] }

当在构建器上调用方法而不带参数时,一个空的 JSON 对象与该键相关联

builder.element()
// produces
{ "element": {} }

您也可以传递一个 map 和一个闭包参数

builder.person(name: "Guillaume", age: 33) { town "Paris" }

// produces
{"name": "Guillaume", "age": 33, "town": "Paris}

以下调用,带有 map 和值,在 JSON 中没有有意义的表示(与 XML 不同),并会触发 JsonException

shouldFail(JsonException) {
    builder.elem(a: 1, b: 2, "some text value")
}

在 map 和闭包中出现重叠键的情况下,闭包优先 - 此规则的视觉线索是闭包出现在 map 键/值对“之后”。

使用 JSON 本提案建议创建一个 JsonSlurper 类,它可以从字符串(以非流式方式)读取 JSON 并生成表示 JSON 对象和数组的 map 和列表层次结构。

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 的 API 应该在 parse* 方法变体方面与 XmlParser/XmlSlurper 提供的功能密切匹配。

更新历史

3 (2011-02-02)

从 Codehaus wiki 中提取的版本

4 (2018-10-16)

大量细微调整