Недавно я использовал JsonBuilder в одном из моих проектов и изначально испытывал некоторые трудности в понимании того, как он работает. Я предположил, что JsonBuilder работает аналогично MarkupBuilder, но, как я быстро выяснил, на самом деле это не так.
Давайте возьмем простой пример. Предположим, у нас есть класс Message, который мы хотим сериализовать в разметку XML и JSON.
1
2
3
4
5
6
7
8
9
|
@groovy .transform.Canonical class Message { long id String sender String text } assert 'Message(23, me, some text)' == new Message( 23 , 'me' , 'some text' ).toString() |
Здесь я использовал Groovy 1.8.0 @Canonical аннотацию, обеспечивающую автоматическое toString () , equals () и hashCode () и конструктор кортежа (упорядоченный) .
Давайте сериализуем ряд сообщений в XML.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
def messages = [ new Message( 23 , 'me' , 'some text' ), new Message( 24 , 'me' , 'some other text' ), new Message( 25 , 'me' , 'same text' )] def writer = new StringWriter() def xml = new groovy.xml.MarkupBuilder( writer ) xml.messages() { messages.each { Message m -> message( id : m.id, sender : m.sender, text : m.text )} } assert writer.toString() == "" " <messages> <message id= '23' sender= 'me' text= 'some text' /> <message id= '24' sender= 'me' text= 'some other text' /> <message id= '25' sender= 'me' text= 'same text' /> </messages> "" ".trim() |
Ну, это было довольно просто. Давайте попробуем сделать то же самое с JSON.
01
02
03
04
05
06
07
08
09
10
|
def json = new groovy.json.JsonBuilder() json.messages() { messages.each { Message m -> message( id : m.id, sender : m.sender, text : m.text )} } assert json.toString() == '{"messages":{"message":{"id":25,"sender":"me","text":"same text"}}}' |
Вау, куда делись все остальные сообщения? Почему только одно последнее сообщение в списке было сериализовано?
Как насчет этого:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
json = new groovy.json.JsonBuilder() json.messages() { message { id 23 sender 'me' text 'some text' } message { id 24 sender 'me' text 'some other text' } } assert json.toString() == '{"messages":{"message":{"id":24,"sender":"me","text":"some other text"}}}' |
Та же история. Сначала я был озадачен, но затем исходный код JsonBuilder показал, что каждый вызов переопределяет предыдущий контент:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
JsonBuilder(content = null ) { this .content = content } def call(Map m) { this .content = m return content } def call(List l) { this .content = l return content } def call(Object... args) { this .content = args.toList() return this .content } def call(Closure c) { this .content = JsonDelegate.cloneDelegateAndGetContent(c) return content } |
Как видите, нужно вызвать JsonBuilder ровно один раз, передав ему Map , List , varargs или Closure . Это сильно отличает JsonBuilder от MarkupBuilder, который можно обновлять столько раз, сколько необходимо. Это может быть вызвано самим JSON, формат которого более строг, чем разметка XML свободной формы: то, что начиналось как карта JSON с одним Сообщением , не может быть внезапно превращено в массив Сообщений .
Аргумент, передаваемый в JsonBuilder (Map, List, varargs или Closure), также может быть указан в конструкторе, поэтому вообще не нужно вызывать конструктор. Вы можете просто инициализировать его с соответствующей структурой данных и сразу вызвать toString () . Давайте попробуем это!
01
02
03
04
05
06
07
08
09
10
|
def listOfMaps = messages.collect{ Message m -> [ id : m.id, sender : m.sender, text : m.text ]} assert new groovy.json.JsonBuilder( listOfMaps ).toString() == '' '[{ "id" : 23 , "sender" : "me" , "text" : "some text" }, { "id" : 24 , "sender" : "me" , "text" : "some other text" }, { "id" : 25 , "sender" : "me" , "text" : "same text" }] '' '. readLines()*.trim().join() |
Теперь это работает 🙂 После преобразования списка сообщений в список Карт и отправки их в JsonBuilder за один раз, сгенерированная строка содержит все сообщения из списка. Весь приведенный выше код доступен в веб-консоли Groovy, поэтому вы можете попробовать его.
Кстати, для просмотра онлайн JSON я рекомендую отличное приложение « JSON Visualization », созданное Крисом Нильсеном. « Online JSON Viewer » — еще один популярный вариант, но я предпочитаю первый. А для автономного использования « JSON Viewer » делает хороший плагин Fiddler .
PS
Если вам нужно прочитать этот JSON на стороне клиента, отправив, скажем, Ajax GET-запрос, это легко сделать с помощью jQuery.get () :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<script type = "text/javascript" > var j = jQuery; j( function () { j.get( 'url' , { timestamp: new Date().getTime() }, function ( messages ){ j.each( messages, function ( index, m ) { alert( "[" + m. id + "][" + m.sender + "][" + m.text + "]" ); }); }, 'json' ); }); < /script > |
Здесь я использую хитрый прием ярлыка j, чтобы не вводить слишком много раз jQuery, когда использование $ не является опцией.
Ссылка: Groovy 1.8.0 — познакомьтесь с JsonBuilder! от нашего партнера JCG