1. JSON 处理方式

Groovy 中集成 JSON 与 对象之间转换的功能。 在 groovy.json 包中的类专门用于 JSON 序列化及解析工作.

1.1. JsonSlurper

JsonSlurper 用于将 JSON 字符串转换为 Groovy 数据结构,如:maps, lists, 以及原始类型 Integer , Double, BooleanString.

其类中有大量的 parse 以及如: parseTextparseFile 等方法。 下面的例子中将使用 parseText 方法来解析 JSON 字符串,并将其转换为 list 或 map 对象。 The class comes with a bunch of overloaded parse methods plus some special methods such as parseText, parseFile and others. For the next example we will use the parseText method. It parses a JSON String and recursively converts it to a list or map of objects. The other parse* methods are similar in that they return a JSON String but for different parameter types.

def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText('{ "name": "John Doe" } /* some comment */')

assert object instanceof Map
assert object.name == 'John Doe'

这里的返回结果为 map , 可以像普通 Groovy 对象一样使用。 JsonSlurper 解析的 Json 字符串遵循 ECMA-404 JSON 交换标准 , 增加了对于注解及日期的支持。

In addition to maps JsonSlurper supports JSON arrays which are converted to lists. 除了 map,JsonSlurper 也支持将 JSON 数组转换为 lists .

def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText('{ "myList": [4, 8, 15, 16, 23, 42] }')

assert object instanceof Map
assert object.myList instanceof List
assert object.myList == [4, 8, 15, 16, 23, 42]

JSON 标准支持以下原始数据类型:string, number, object, true, false, null. JsonSlurper 会将它们转换为对应的 Groovy 类型。

def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText '''
    { "simple": 123,
      "fraction": 123.66,
      "exponential": 123e12
    }'''

assert object instanceof Map
assert object.simple.class == Integer
assert object.fraction.class == BigDecimal
assert object.exponential.class == BigDecimal

JsonSlurper 返回 Groovy 对象, 其返回结果符合 GPath 表达式。GPath 是一种功能很强的表达式语言,并通过 multiple slurpers 可以支持不同的 数据格式,例如:XmlSlurper 用于支持 xml

想了解更多的细节,可以查看 GPath表达式 这一章节。

下面是 JSON 类型与对应的 Groovy 数据类型,对照表:

JSON Groovy
Stirng java.lang.String
number java.lang.BigDecimal or java.lang.Integer
object java.util.LinkedHashMap
array java.util.ArrayList
true true
false false
null null
date java.util.Date yyyy-MM-dd’T’HH:mm:ssZ

Whenever a value in JSON is null, JsonSlurper supplements it with the Groovy null value. This is in contrast to other JSON parsers that represent a null value with a library-provided singleton object.

1.1.1. Parser Variants

JsonSlurper 附带了一些解析器实现。每种解析器适用于不同的需求,在特定的场景中,默认的解析器并不一定是最好的解决方案, 这里有一些解析器的简单介绍:

  • JsonParserCharArray 解析器,将 JSON 字符串,基于字符数组方式处理,在处理过程中拷贝字符的子数组并处理(这种机制称为:chopping).

The JsonFastParser is a special variant of the JsonParserCharArray and is the fastest parser. However, it is not the default parser for a reason. JsonFastParser is a so-called index-overlay parser. During parsing of the given JSON String it tries as hard as possible to avoid creating new char arrays or String instances. It keeps pointers to the underlying original character array only. In addition, it defers object creation as late as possible. If parsed maps are put into long-term caches care must be taken as the map objects might not be created and still consist of pointer to the original char buffer only. However, JsonFastParser comes with a special chop mode which dices up the char buffer early to keep a small copy of the original buffer. Recommendation is to use the JsonFastParser for JSON buffers under 2MB and keeping the long-term cache restriction in mind. (JsonFastParser 是基于 JsonParserCharArray 的扩展,它是最快速的解析器。其不是默认解析器,也是有一定原因。JsonFastParser 是所谓指数覆盖解析器。在解析 JSON 字符串的时候,其尽可能避免创建新的字符数组或字符串。仅保持其指针在愿字符数组上。此外,也尽可能推迟对象的创建,)

  • The JsonParserLax is a special variant of the JsonParserCharArray parser. It has similar performance characteristics as JsonFastParser but differs in that it isn’t exclusively relying on the ECMA-404 JSON grammar. For example it allows for comments, no quote strings etc.
  • The JsonParserUsingCharacterSource is a special parser for very large files. It uses a technique called “character windowing” to parse large JSON files (large means files over 2MB size in this case) with constant performance characteristics.

JsonSlurper 的默认解析器实现是 JsonParserCharArray. 下表中列举了 JsonParserType 与 其实现的对照关系:

Implementation Constant
JsonParserCharArray JsonParserType#CHAR_BUFFER
JsonFastParser JsonParserType#INDEX_OVERLAY
JsonParserLax JJsonParserType#LAX
JsonParserUsingCharacterSource JsonParserType#CHARACTER_SOURCE

通过调用 JsonSlurper#setType() 来设置 JsonParserType 可以很方便的修改解析器的实现。

def jsonSlurper = new JsonSlurper(type: JsonParserType.INDEX_OVERLAY)
def object = jsonSlurper.parseText('{ "myList": [4, 8, 15, 16, 23, 42] }')

assert object instanceof Map
assert object.myList instanceof List
assert object.myList == [4, 8, 15, 16, 23, 42]

1.2. JsonOutput

JsonOutput 主要用于将 Groovy 对象序列化为 JSON 字符串。

JsonOutput is responsible for serialising Groovy objects into JSON strings. It can be seen as companion object to JsonSlurper, being a JSON parser.

JsonOutput 中有一些重载,静态 toJson 方法。每种 toJson 实现都带有不同的参数。静态可以直接使用,或通过静态引入后使用。

toJson 返回结果返回 JSON 格式的字符串。

def json = JsonOutput.toJson([name: 'John Doe', age: 42])

assert json == '{"name":"John Doe","age":42}'

JsonOutput 不仅仅支持原始类型,maps,lists,还可以支持 POGOs 序列化。

class Person { String name }

def json = JsonOutput.toJson([ new Person(name: 'John'), new Person(name: 'Max') ])

assert json == '[{"name":"John"},{"name":"Max"}]'

上面例子中,JSON 的默认输出没有使用 pretty printed.

def json = JsonOutput.toJson([name: 'John Doe', age: 42])

assert json == '{"name":"John Doe","age":42}'

assert JsonOutput.prettyPrint(json) == '''\
{
    "name": "John Doe",
    "age": 42
}'''.stripIndent()

prettyPrint 方法只有一个字符串输入参数,它不与 JsonOutput 中的其它方法结合使用,其可以处理任何的 JSON 格式字符串。

Groovy 中还可以使用 JsonBuilder 或 StreamingJsonBuilder 创建 JSON. 这两种方式提供 DSL 通过其定制对象的图谱,并将其转化为 JSON 。

For more details on builders, have a look at the builders chapter which covers both JsonBuilder and StreamingJsonBuilder. 如希望了解更多的细节,可以查看它们对应的章节,JsonBuilderStreamingJsonBuilder