This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 92cbb3f39c minor refactor: junit5 and doco improvements (typed
checking section)
92cbb3f39c is described below
commit 92cbb3f39ce6446216cff8c563c1b7316baa31c5
Author: Paul King <[email protected]>
AuthorDate: Mon Apr 13 15:37:01 2026 +1000
minor refactor: junit5 and doco improvements (typed checking section)
---
.../groovy-json/src/spec/doc/json-userguide.adoc | 44 ++++++++++++++
.../groovy-json/src/spec/test/json/JsonTest.groovy | 67 +++++++++++++++++++++-
2 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
b/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
index 2c12d4efa2..6700231df0 100644
--- a/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
+++ b/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
@@ -217,6 +217,50 @@
include::../test/json/JsonTest.groovy[tags=pretty_print,indent=0]
`prettyPrint` takes a `String` as single parameter; therefore, it can be
applied on arbitrary JSON `String` instances, not only the result of
`JsonOutput.toJson`.
+== Typed JSON Parsing
+
+Since `JsonSlurper` parses JSON values into their natural JVM types
+(`Integer`, `BigDecimal`, `Boolean`, `List`, `Map`), Groovy's built-in
+`as` coercion works well for converting parsed JSON directly into
+typed objects -- no additional dependencies are required:
+
+[source,groovy]
+----
+include::../test/json/JsonTest.groovy[tags=typed_classes,indent=0]
+----
+
+[source,groovy]
+----
+include::../test/json/JsonTest.groovy[tags=typed_coercion,indent=0]
+----
+
+Nested objects are automatically coerced:
+
+[source,groovy]
+----
+include::../test/json/JsonTest.groovy[tags=typed_coercion_nested,indent=0]
+----
+
+Enum values are also handled:
+
+[source,groovy]
+----
+include::../test/json/JsonTest.groovy[tags=typed_coercion_enum,indent=0]
+----
+
+This covers most common use cases. For advanced scenarios -- such as
+typed element collections (`List<Item>`), date/time parsing, or
+annotation-driven property mapping (`@JsonProperty`, `@JsonFormat`) --
+use `jackson-databind` directly:
+
+[source,groovy]
+----
+@Grab('com.fasterxml.jackson.core:jackson-databind')
+import com.fasterxml.jackson.databind.ObjectMapper
+
+def config = new ObjectMapper().readValue(jsonString, ServerConfig)
+----
+
=== Builders
Another way to create JSON from Groovy is to use `JsonBuilder` or
`StreamingJsonBuilder`. Both builders provide a
diff --git a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
index 02b686381e..abfa0c29c8 100644
--- a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
+++ b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
@@ -21,9 +21,12 @@ package json
import groovy.json.JsonOutput
import groovy.json.JsonParserType
import groovy.json.JsonSlurper
-import groovy.test.GroovyTestCase
+import org.junit.jupiter.api.Test
-class JsonTest extends GroovyTestCase {
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
+
+class JsonTest {
void testParseText() {
// tag::parse_text[]
@@ -177,4 +180,64 @@ class JsonTest extends GroovyTestCase {
// end::pretty_print[]
}
+ // tag::typed_classes[]
+ static class ServerConfig {
+ String host
+ int port
+ boolean debug
+ }
+
+ static class AppConfig {
+ String name
+ ServerConfig server
+ }
+
+ enum Color { RED, GREEN, BLUE }
+
+ static class Item { String name; Color color }
+ // end::typed_classes[]
+
+ void testTypedCoercion() {
+ // tag::typed_coercion[]
+ def json = '{"host":"localhost","port":8080,"debug":true}'
+ def config = new JsonSlurper().parseText(json) as ServerConfig
+
+ assert config instanceof ServerConfig
+ assert config.host == 'localhost'
+ assert config.port == 8080
+ assert config.debug == true
+ // end::typed_coercion[]
+ }
+
+ void testTypedCoercionNested() {
+ // tag::typed_coercion_nested[]
+ def json =
'{"name":"myapp","server":{"host":"localhost","port":9090,"debug":false}}'
+ def config = new JsonSlurper().parseText(json) as AppConfig
+
+ assert config.name == 'myapp'
+ assert config.server instanceof ServerConfig
+ assert config.server.host == 'localhost'
+ assert config.server.port == 9090
+ // end::typed_coercion_nested[]
+ }
+
+ void testTypedCoercionEnum() {
+ // tag::typed_coercion_enum[]
+ def item = new
JsonSlurper().parseText('{"name":"widget","color":"GREEN"}') as Item
+ assert item.color == Color.GREEN
+ // end::typed_coercion_enum[]
+ }
+
+ void testJacksonDirectUsage() {
+ // tag::jackson_direct[]
+ // For advanced cases (typed collections, date parsing, @JsonProperty),
+ // use jackson-databind directly:
+ //
+ // @Grab('com.fasterxml.jackson.core:jackson-databind')
+ // import com.fasterxml.jackson.databind.ObjectMapper
+ //
+ // def config = new ObjectMapper().readValue(jsonString, ServerConfig)
+ // end::jackson_direct[]
+ }
+
}