http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy index b320939..28067a6 100644 --- a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy +++ b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy @@ -94,6 +94,74 @@ class JsonTest extends GroovyTestCase { ''' } + void testJsonOutputWithGenerator() { + assertScript ''' + import groovy.json.* + + // tag::json_output_generator[] + class Person { + String name + String title + int age + String password + Date dob + URL favoriteUrl + } + + Person person = new Person(name: 'John', title: null, age: 21, password: 'secret', + dob: Date.parse('yyyy-MM-dd', '1984-12-15'), + favoriteUrl: new URL('http://groovy-lang.org/')) + + def generator = new JsonGenerator.Options() + .excludeNulls() + .dateFormat('MM@dd@yyyy') + .excludeFieldsByName('age', 'password') + .excludeFieldsByType(URL) + .build() + + assert generator.toJson(person) == '{"dob":"12@15@1984","name":"John"}' + // end::json_output_generator[] + ''' + } + + void testJsonOutputConverter() { + assertScript ''' + import groovy.json.* + import static groovy.test.GroovyAssert.shouldFail + + // tag::json_output_converter[] + class Person { + String name + URL favoriteUrl + } + + Person person = new Person(name: 'John', favoriteUrl: new URL('http://groovy-lang.org/json.html#_jsonoutput')) + + def generator = new JsonGenerator.Options() + .addConverter(URL) { URL u, String key -> + if (key == 'favoriteUrl') { + '"' + u.getHost() + '"' + } else { + JsonOutput.toJson(u) + } + } + .build() + + assert generator.toJson(person) == '{"favoriteUrl":"groovy-lang.org","name":"John"}' + + // No key available when generating a JSON Array + def list = [new URL('http://groovy-lang.org/json.html#_jsonoutput')] + assert generator.toJson(list) == '["http://groovy-lang.org/json.html#_jsonoutput"]' + + // First parameter to the converter must match the type for which it is registered + shouldFail(IllegalArgumentException) { + new JsonGenerator.Options() + .addConverter(Date) { Calendar cal -> } + } + // end::json_output_converter[] + ''' + } + void testPrettyPrint() { // tag::pretty_print[] def json = JsonOutput.toJson([name: 'John Doe', age: 42])
http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy b/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy index c9bb0fe..7deb2ae 100644 --- a/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy +++ b/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy @@ -18,8 +18,6 @@ */ package json -import groovy.util.GroovyTestCase - class StreamingJsonBuilderTest extends GroovyTestCase { void testStreamingJsonBuilder() { @@ -72,4 +70,37 @@ class StreamingJsonBuilderTest extends GroovyTestCase { // end::json_assert[] """ } + + void testStreamingJsonBuilderWithGenerator() { + assertScript ''' + import groovy.json.* + // tag::streaming_json_builder_generator[] + def generator = new JsonGenerator.Options() + .excludeNulls() + .excludeFieldsByName('make', 'country', 'record') + .excludeFieldsByType(Number) + .addConverter(URL) { url -> '"http://groovy-lang.org"' } + .build() + + StringWriter writer = new StringWriter() + StreamingJsonBuilder builder = new StreamingJsonBuilder(writer, generator) + + builder.records { + car { + name 'HSV Maloo' + make 'Holden' + year 2006 + country 'Australia' + homepage new URL('http://example.org') + record { + type 'speed' + description 'production pickup truck with speed of 271kph' + } + } + } + + assert writer.toString() == '{"records":{"car":{"name":"HSV Maloo","homepage":"http://groovy-lang.org"}}}' + // end::streaming_json_builder_generator[] + ''' + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy index d19718e..8915f55 100644 --- a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy +++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy @@ -63,6 +63,17 @@ class CharBufTest extends GroovyTestCase { assert str == '" \\\\ "' } + void testDisableUnicodeEscaping() { + String str = CharBuf.create(0).addJsonEscapedString("Ãric").toString() + assert str == '"\\u00c9ric"' + + str = CharBuf.create(0).addJsonEscapedString("Ãric", false).toString() + assert str == '"\\u00c9ric"' + + str = CharBuf.create(0).addJsonEscapedString("Ãric", true).toString() + assert str == '"Ãric"' + } + /** * https://issues.apache.org/jira/browse/GROOVY-6937 * https://issues.apache.org/jira/browse/GROOVY-6852 @@ -84,4 +95,28 @@ class CharBufTest extends GroovyTestCase { result = new JsonBuilder(obj).toString() assert result == /["${'\\u20ac' * 20_000}"]/ } + + void testRemoveLastChar() { + CharBuf buffer + + buffer = CharBuf.create(8).add('value1,') + buffer.removeLastChar() + assert buffer.toString() == 'value1' + + buffer = CharBuf.create(4) + buffer.removeLastChar() + assert buffer.toString() == '' + + buffer = CharBuf.create(8).add('[]') + buffer.removeLastChar((char)',') + assert buffer.toString() == '[]' + + buffer = CharBuf.create(8).add('[val,') + buffer.removeLastChar((char)',') + assert buffer.toString() == '[val' + + buffer = CharBuf.create(32).add('[one,two,three,four,') + buffer.removeLastChar((char)',') + assert buffer.toString() == '[one,two,three,four' + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy new file mode 100644 index 0000000..38a73fa --- /dev/null +++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CustomJsonGeneratorTest.groovy @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package groovy.json + +import groovy.json.JsonGenerator.Converter +import groovy.json.JsonGenerator.Options +import groovy.json.internal.CharBuf + +/** + * Tests extensibility of JsonGenerator and associated classes + */ +class CustomJsonGeneratorTest extends GroovyTestCase { + + void testCustomGenerator() { + def generator = new CustomJsonOptions() + .excludeNulls() + .lowerCaseFieldNames() + .addCustomConverter(new CustomJsonConverter()) + .build() + + assert generator.toJson(['one', null, 'two', null]) == '["one","two"]' + assert generator.toJson(['Foo':'test1', 'BAR':'test2']) == '{"foo":"test1","bar":"test2"}' + assert generator.toJson(['foo': new CustomFoo()]) == '{"foo":"CustomFoo from CustomJsonConverter"}' + } + + static class CustomJsonOptions extends Options { + boolean lowerCaseFieldNames + CustomJsonOptions lowerCaseFieldNames() { + lowerCaseFieldNames = true + return this + } + CustomJsonOptions addCustomConverter(Converter converter) { + converters.add(converter) + return this + } + @Override + CustomJsonGenerator build() { + return new CustomJsonGenerator(this) + } + } + + static class CustomJsonGenerator extends DefaultJsonGenerator { + boolean lowerCaseFieldNames + CustomJsonGenerator(CustomJsonOptions opts) { + super(opts) + lowerCaseFieldNames = opts.lowerCaseFieldNames + } + @Override + protected void writeMapEntry(String key, Object value, CharBuf buffer) { + String newKey = (lowerCaseFieldNames) ? key.toLowerCase() : key + super.writeMapEntry(newKey, value, buffer) + } + } + + static class CustomJsonConverter implements Converter { + @Override + boolean handles(Class<?> type) { + return CustomFoo.isAssignableFrom(type) + } + + @Override + CharSequence convert(Object value) { + return convert(value, null) + } + + @Override + CharSequence convert(Object value, String key) { + return '"CustomFoo from CustomJsonConverter"' + } + } + + static class CustomFoo {} +} http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/test/groovy/groovy/json/DefaultJsonGeneratorTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/DefaultJsonGeneratorTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/DefaultJsonGeneratorTest.groovy new file mode 100644 index 0000000..167ce31 --- /dev/null +++ b/subprojects/groovy-json/src/test/groovy/groovy/json/DefaultJsonGeneratorTest.groovy @@ -0,0 +1,283 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package groovy.json + +class DefaultJsonGeneratorTest extends GroovyTestCase { + + void testExcludesNullValues() { + def generator = new JsonGenerator.Options() + .excludeNulls() + .build() + + def json = generator.toJson(new JsonObject(name: 'test', properties: null)) + assert json == '{"name":"test"}' + + json = generator.toJson([field1: null, field2: "test"]) + assert json == '{"field2":"test"}' + + assert generator.toJson([null]) == '[]' + assert generator.toJson(['a','b','c','d', null]) == '["a","b","c","d"]' + assert generator.toJson(['a', null, null, null, null]) == '["a"]' + assert generator.toJson(['a', null, null, null, 'e']) == '["a","e"]' + + def jsonArray = ["foo", null, "bar"] + def jsonExpected = '["foo","bar"]' + assert generator.toJson(jsonArray) == jsonExpected + assert generator.toJson(jsonArray as Object[]) == jsonExpected + assert generator.toJson(jsonArray.iterator()) == jsonExpected + assert generator.toJson((Iterable)jsonArray) == jsonExpected + + assert generator.toJson((Boolean)null) == '' + assert generator.toJson((Number)null) == '' + assert generator.toJson((Character)null) == '' + assert generator.toJson((String)null) == '' + assert generator.toJson((Date)null) == '' + assert generator.toJson((Calendar)null) == '' + assert generator.toJson((UUID)null) == '' + assert generator.toJson((Closure)null) == '' + assert generator.toJson((Expando)null) == '' + assert generator.toJson((Object)null) == '' + assert generator.toJson((Map)null) == '' + } + + void testCustomDateFormat() { + def generator = new JsonGenerator.Options() + .dateFormat('yyyy-MM') + .build() + + Date aDate = Date.parse('yyyy-MM-dd', '2016-07-04') + assert generator.toJson(aDate) == '"2016-07"' + + def jsonObject = new JsonObject(name: 'test', properties: [startDate: aDate]) + def json = generator.toJson(jsonObject) + assert json.contains('{"startDate":"2016-07"}') + + def jsonArray = ["foo", aDate, "bar"] + def jsonExpected = '["foo","2016-07","bar"]' + assert generator.toJson(jsonArray) == jsonExpected + assert generator.toJson(jsonArray as Object[]) == jsonExpected + assert generator.toJson(jsonArray.iterator()) == jsonExpected + assert generator.toJson((Iterable)jsonArray) == jsonExpected + } + + void testDateFormatBadInput() { + shouldFail(NullPointerException) { + new JsonGenerator.Options().dateFormat(null) + } + shouldFail(IllegalArgumentException) { + new JsonGenerator.Options().dateFormat('abcde') + } + shouldFail(NullPointerException) { + new JsonGenerator.Options().timezone(null) + } + } + + void testConverters() { + def generator = new JsonGenerator.Options() + .addConverter(JsonCyclicReference) { object, key -> + return '"JsonCyclicReference causes a stackoverflow"' + } + .addConverter(Date) { object -> + return '"4 score and 7 years ago"' + } + .addConverter(Calendar) { object -> + return '"22 days ago"' + } + .build() + + assert generator.toJson(new Date()) == '"4 score and 7 years ago"' + + def ref = new JsonBar('bar', new Date()) + def json = generator.toJson(ref) + assert json.contains('"lastVisit":"4 score and 7 years ago"') + assert json.contains('"cycle":"JsonCyclicReference causes a stackoverflow"') + + def jsonArray = ["foo", new JsonCyclicReference(), "bar", new Date()] + def jsonExpected = '["foo","JsonCyclicReference causes a stackoverflow","bar","4 score and 7 years ago"]' + assert generator.toJson(jsonArray) == jsonExpected + assert generator.toJson(jsonArray as Object[]) == jsonExpected + assert generator.toJson(jsonArray.iterator()) == jsonExpected + assert generator.toJson((Iterable)jsonArray) == jsonExpected + + assert generator.toJson([timeline: Calendar.getInstance()]) == '{"timeline":"22 days ago"}' + } + + void testConverterAddedLastTakesPrecedence() { + def options = new JsonGenerator.Options() + def c1 = { 'c1' } + def c2 = { 'c2' } + options.addConverter(URL, {}) + options.addConverter(Date, c1) + options.addConverter(Calendar, {}) + options.addConverter(Date, c2) + options.addConverter(java.sql.Date, {}) + + assert optio...@converters.size() == 4 + assert options.@converters[2].convert(null) == 'c2' + assert !optio...@converters.find { it.convert(null) == 'c1' } + } + + void testConvertersBadInput() { + shouldFail(NullPointerException) { + new JsonGenerator.Options().addConverter(null, null) + } + shouldFail(NullPointerException) { + new JsonGenerator.Options().addConverter(Date, null) + } + shouldFail(IllegalArgumentException) { + new JsonGenerator.Options().addConverter(Date, {-> 'no args closure'}) + } + shouldFail(IllegalArgumentException) { + new JsonGenerator.Options().addConverter(Date, { UUID obj -> 'mis-matched types'}) + } + shouldFail(IllegalArgumentException) { + new JsonGenerator.Options().addConverter(Date, { Date obj, UUID cs -> 'mis-matched types'}) + } + } + + void testExcludesFieldsByName() { + def generator = new JsonGenerator.Options() + .excludeFieldsByName('name') + .build() + + def ref = new JsonObject(name: 'Jason', properties: ['foo': 'bar']) + def json = generator.toJson(ref) + assert json == '{"properties":{"foo":"bar"}}' + + def jsonArray = ["foo", ["bar":"test","name":"Jane"], "baz"] + def jsonExpected = '["foo",{"bar":"test"},"baz"]' + assert generator.toJson(jsonArray) == jsonExpected + assert generator.toJson(jsonArray as Object[]) == jsonExpected + assert generator.toJson(jsonArray.iterator()) == jsonExpected + assert generator.toJson((Iterable)jsonArray) == jsonExpected + + def excludeList = ['foo', 'bar', "${'zoo'}"] + generator = new JsonGenerator.Options() + .excludeFieldsByName(excludeList) + .build() + + json = generator.toJson([foo: 'one', bar: 'two', baz: 'three', zoo: 'four']) + assert json == '{"baz":"three"}' + } + + void testExcludeFieldsByNameBadInput() { + shouldFail(NullPointerException) { + new JsonGenerator.Options().excludeFieldsByName(null) + } + } + + void testExcludeFieldsByNameShouldIgnoreNulls() { + def opts = new JsonGenerator.Options() + .excludeFieldsByName('foo', null, "${'bar'}") + .excludeFieldsByName([new StringBuilder('one'), null, 'two']) + + assert op...@excludedfieldnames.size() == 4 + assert !opts.@excludedFieldNames.contains(null) + } + + void testExcludesFieldsByType() { + def generator = new JsonGenerator.Options() + .excludeFieldsByType(Date) + .build() + + def ref = [name: 'Jason', dob: new Date(), location: 'Los Angeles'] + assert generator.toJson(ref) == '{"name":"Jason","location":"Los Angeles"}' + + def jsonArray = ["foo", "bar", new Date()] + def jsonExpected = '["foo","bar"]' + assert generator.toJson(jsonArray) == jsonExpected + assert generator.toJson(jsonArray as Object[]) == jsonExpected + assert generator.toJson(jsonArray.iterator()) == jsonExpected + assert generator.toJson((Iterable)jsonArray) == jsonExpected + + generator = new JsonGenerator.Options() + .excludeFieldsByType(Integer) + .excludeFieldsByType(Boolean) + .excludeFieldsByType(Character) + .excludeFieldsByType(Calendar) + .excludeFieldsByType(UUID) + .excludeFieldsByType(URL) + .excludeFieldsByType(Closure) + .excludeFieldsByType(Expando) + .excludeFieldsByType(TreeMap) + .excludeFieldsByType(Date) + .build() + + assert generator.toJson(Integer.valueOf(7)) == '' + assert generator.toJson(Boolean.TRUE) == '' + assert generator.toJson((Character)'c') == '' + assert generator.toJson(Calendar.getInstance()) == '' + assert generator.toJson(UUID.randomUUID()) == '' + assert generator.toJson(new URL('http://groovy-lang.org')) == '' + assert generator.toJson({ url new URL('http://groovy-lang.org') }) == '' + assert generator.toJson(new Expando()) == '' + assert generator.toJson(new TreeMap()) == '' + assert generator.toJson(new java.sql.Date(new Date().getTime())) == '' + + def excludeList = [URL, Date] + generator = new JsonGenerator.Options() + .excludeFieldsByType(excludeList) + .build() + + def json = generator.toJson([foo: new Date(), bar: 'two', baz: new URL('http://groovy-lang.org')]) + assert json == '{"bar":"two"}' + } + + void testExcludeFieldsByTypeBadInput() { + shouldFail(NullPointerException) { + new JsonGenerator.Options().excludeFieldsByType(null) + } + } + + void testExcludeFieldsByTypeShouldIgnoreNulls() { + def opts = new JsonGenerator.Options() + .excludeFieldsByType(Date, null, URL) + .excludeFieldsByType([Calendar, null, TreeMap]) + + assert op...@excludedfieldtypes.size() == 4 + assert !opts.@excludedFieldTypes.contains(null) + } + + void testDisableUnicodeEscaping() { + def json = new JsonGenerator.Options() + .disableUnicodeEscaping() + .build() + + String unicodeString = 'ÎΡÎΩΠÎÎÎÎÎ' + assert json.toJson([unicodeString]) == """["${unicodeString}"]""" + + assert json.toJson(['KÃY':'VALUE']) == '{"KÃY":"VALUE"}' + } + +} + +class JsonBar { + String favoriteDrink + Date lastVisit + JsonCyclicReference cycle = new JsonCyclicReference() + JsonBar(String favoriteDrink, Date lastVisit) { + this.favoriteDrink = favoriteDrink + this.lastVisit = lastVisit + } +} + +class JsonCyclicReference { + static final DEFAULT = new JsonCyclicReference() + JsonCyclicReference() { } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy index ec643f0..79c88e3 100644 --- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy +++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy @@ -402,4 +402,31 @@ class JsonBuilderTest extends GroovyTestCase { assert new JsonBuilder({'\1' 0}).toString() == '{"\\u0001":0}' assert new JsonBuilder({'\u0002' 0}).toString() == '{"\\u0002":0}' } + + void testWithGenerator() { + def generator = new JsonGenerator.Options() + .excludeNulls() + .dateFormat('yyyyMM') + .excludeFieldsByName('secretKey', 'creditCardNumber') + .excludeFieldsByType(URL) + .addConverter(java.util.concurrent.atomic.AtomicBoolean) { ab -> ab.toString() } + .build() + + def json = new JsonBuilder(generator) + + json.payload { + id 'YT-1234' + location null + secretKey 'J79-A25' + creditCardNumber '123-444-789-2233' + site new URL('http://groovy-lang.org') + isActive new java.util.concurrent.atomic.AtomicBoolean(true) + } + + assert json.toString() == '{"payload":{"id":"YT-1234","isActive":true}}' + + json = new JsonBuilder(['foo', null, 'bar', new URL('http://groovy-lang.org')], generator) + assert json.toString() == '["foo","bar"]' + } + } http://git-wip-us.apache.org/repos/asf/groovy/blob/13202599/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy index 25ac0ae..a3cf4d8 100644 --- a/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy +++ b/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy @@ -496,4 +496,54 @@ class StreamingJsonBuilderTest extends GroovyTestCase { } } } + + void testWithGenerator() { + def generator = new JsonGenerator.Options() + .excludeNulls() + .dateFormat('yyyyMM') + .excludeFieldsByName('secretKey', 'creditCardNumber') + .excludeFieldsByType(URL) + .addConverter(java.util.concurrent.atomic.AtomicBoolean) { ab -> ab.toString() } + .build() + + new StringWriter().with { w -> + def builder = new StreamingJsonBuilder(w, generator) + + builder.payload { + id 'YT-1234' + location null + secretKey 'J79-A25' + creditCardNumber '123-444-789-2233' + site new URL('http://groovy-lang.org') + isActive new java.util.concurrent.atomic.AtomicBoolean(true) + } + + assert w.toString() == '{"payload":{"id":"YT-1234","isActive":true}}' + } + } + + @CompileStatic + void testWithGeneratorCompileStatic() { + def generator = new JsonGenerator.Options() + .excludeNulls() + .dateFormat('yyyyMM') + .excludeFieldsByName('secretKey', 'creditCardNumber') + .excludeFieldsByType(URL) + .addConverter(java.util.concurrent.atomic.AtomicBoolean) { ab -> ab.toString() } + .build() + + new StringWriter().with { w -> + def builder = new StreamingJsonBuilder(w, generator) + builder.call('payload') { + call 'id', 'YT-1234' + call 'location', (String)null + call 'secretKey', 'J79-A25' + call 'creditCardNumber', '123-444-789-2233' + call 'site', new URL('http://groovy-lang.org') + call 'isActive', new java.util.concurrent.atomic.AtomicBoolean(true) + } + + assert w.toString() == '{"payload":{"id":"YT-1234","isActive":true}}' + } + } }