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

commit 978816738bcaa1f6ddc9e36b3d30abf666d060e2
Author: Paul King <[email protected]>
AuthorDate: Sun Apr 12 15:41:54 2026 +1000

    GROOVY-11925: Improve consistency of TOML functionality
---
 .../src/main/java/groovy/toml/TomlBuilder.java     | 17 +++++
 .../src/main/java/groovy/toml/TomlSlurper.java     | 73 ++++++++++++++++++++++
 .../groovy-toml/src/spec/doc/toml-userguide.adoc   | 25 ++++++++
 .../spec/test/groovy/toml/TomlBuilderTest.groovy   | 24 +++++++
 .../spec/test/groovy/toml/TomlParserTest.groovy    | 48 ++++++++++++++
 5 files changed, 187 insertions(+)

diff --git a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java 
b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java
index a8416a8ae4..c6db8e5599 100644
--- a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java
+++ b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlBuilder.java
@@ -18,6 +18,7 @@
  */
 package groovy.toml;
 
+import com.fasterxml.jackson.dataformat.toml.TomlMapper;
 import groovy.json.JsonBuilder;
 import groovy.lang.Closure;
 import groovy.lang.GroovyObjectSupport;
@@ -45,6 +46,22 @@ public class TomlBuilder extends GroovyObjectSupport 
implements Writable {
         this.jsonBuilder = new JsonBuilder();
     }
 
+    /**
+     * Serializes a typed object to a TOML string using Jackson databinding.
+     * Supports {@code @JsonProperty} and {@code @JsonFormat} annotations.
+     *
+     * @param object the object to serialize
+     * @return the TOML string
+     * @since 6.0.0
+     */
+    public static String toToml(Object object) {
+        try {
+            return new TomlMapper().writeValueAsString(object);
+        } catch (IOException e) {
+            throw new TomlRuntimeException(e);
+        }
+    }
+
     public Object getContent() {
         return jsonBuilder.getContent();
     }
diff --git a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java 
b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java
index ee998284be..4e191215f3 100644
--- a/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java
+++ b/subprojects/groovy-toml/src/main/java/groovy/toml/TomlSlurper.java
@@ -18,10 +18,12 @@
  */
 package groovy.toml;
 
+import com.fasterxml.jackson.dataformat.toml.TomlMapper;
 import groovy.json.JsonSlurper;
 import org.apache.groovy.lang.annotation.Incubating;
 import org.apache.groovy.toml.util.TomlConverter;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -93,4 +95,75 @@ public class TomlSlurper {
         // note: convert to an input stream to allow the support of foreign 
file objects
         return parse(Files.newInputStream(path));
     }
+
+    /**
+     * Parse the content of the specified TOML text into a typed object using 
Jackson databinding.
+     * Supports {@code @JsonProperty} and {@code @JsonFormat} annotations for
+     * property mapping and type conversion.
+     *
+     * @param type the target type
+     * @param toml the content of TOML
+     * @param <T> the target type
+     * @return a typed object
+     * @since 6.0.0
+     */
+    public <T> T parseTextAs(Class<T> type, String toml) {
+        return parseAs(type, new StringReader(toml));
+    }
+
+    /**
+     * Parse TOML from a reader into a typed object.
+     *
+     * @param type the target type
+     * @param reader the reader of TOML
+     * @param <T> the target type
+     * @return a typed object
+     * @since 6.0.0
+     */
+    public <T> T parseAs(Class<T> type, Reader reader) {
+        try (Reader r = reader) {
+            return new TomlMapper().readValue(r, type);
+        } catch (IOException e) {
+            throw new TomlRuntimeException(e);
+        }
+    }
+
+    /**
+     * Parse TOML from an input stream into a typed object.
+     *
+     * @param type the target type
+     * @param stream the input stream of TOML
+     * @param <T> the target type
+     * @return a typed object
+     * @since 6.0.0
+     */
+    public <T> T parseAs(Class<T> type, InputStream stream) {
+        return parseAs(type, new InputStreamReader(stream));
+    }
+
+    /**
+     * Parse TOML from a file into a typed object.
+     *
+     * @param type the target type
+     * @param file the TOML file
+     * @param <T> the target type
+     * @return a typed object
+     * @since 6.0.0
+     */
+    public <T> T parseAs(Class<T> type, File file) throws IOException {
+        return parseAs(type, file.toPath());
+    }
+
+    /**
+     * Parse TOML from a path into a typed object.
+     *
+     * @param type the target type
+     * @param path the path to the TOML file
+     * @param <T> the target type
+     * @return a typed object
+     * @since 6.0.0
+     */
+    public <T> T parseAs(Class<T> type, Path path) throws IOException {
+        return parseAs(type, Files.newInputStream(path));
+    }
 }
diff --git a/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc 
b/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc
index d59ab1935d..a160bc857c 100644
--- a/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc
+++ b/subprojects/groovy-toml/src/spec/doc/toml-userguide.adoc
@@ -90,6 +90,22 @@ The following table gives an overview of the TOML types and 
the corresponding Gr
 Whenever a value in TOML is `null`, `TomlSlurper` supplements it with the 
Groovy `null` value. This is in contrast to other
 TOML parsers that represent a `null` value with a library-provided singleton 
object.
 
+=== Typed parsing
+
+`TomlSlurper` can parse TOML directly into typed objects using Jackson 
databinding.
+Standard Jackson annotations such as `@JsonProperty` and `@JsonFormat` are 
supported
+for property mapping and type conversion:
+
+[source,groovy]
+----
+include::../test/groovy/toml/TomlParserTest.groovy[tags=typed_class,indent=0]
+----
+
+[source,groovy]
+----
+include::../test/groovy/toml/TomlParserTest.groovy[tags=typed_parsing,indent=0]
+----
+
 === Builders
 
 Another way to create TOML from Groovy is to use `TomlBuilder`. The builder 
provide a
@@ -99,3 +115,12 @@ DSL which allows to formulate an object graph which is then 
converted to TOML.
 ----
 include::../test/groovy/toml/TomlBuilderTest.groovy[tags=build_text,indent=0]
 ----
+
+=== Typed writing
+
+`TomlBuilder.toToml(object)` serializes a typed object directly to TOML using 
Jackson databinding:
+
+[source,groovy]
+----
+include::../test/groovy/toml/TomlBuilderTest.groovy[tags=typed_writing,indent=0]
+----
diff --git 
a/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy 
b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy
index e338b3c447..8bca0bc248 100644
--- a/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy
+++ b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlBuilderTest.groovy
@@ -50,4 +50,28 @@ records.car.record.description = 'production pickup truck 
with speed of 271kph'
 '''
         // end::build_text[]
     }
+
+    // tag::typed_writing[]
+    static class ServerConfig {
+        String host
+        int port
+    }
+
+    void testToToml() {
+        def config = new ServerConfig(host: 'localhost', port: 8080)
+        def toml = TomlBuilder.toToml(config)
+        assert toml.contains('host')
+        assert toml.contains('localhost')
+        assert toml.contains('port')
+        assert toml.contains('8080')
+    }
+    // end::typed_writing[]
+
+    void testTypedRoundTrip() {
+        def original = new ServerConfig(host: 'example.com', port: 443)
+        def toml = TomlBuilder.toToml(original)
+        def parsed = new TomlSlurper().parseTextAs(ServerConfig, toml)
+        assert parsed.host == 'example.com'
+        assert parsed.port == 443
+    }
 }
\ No newline at end of file
diff --git 
a/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy 
b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy
index dacef27779..7bcaaeb329 100644
--- a/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy
+++ b/subprojects/groovy-toml/src/spec/test/groovy/toml/TomlParserTest.groovy
@@ -107,4 +107,52 @@ jdk = "oraclejdk8"
         assert ['openjdk10', 'oraclejdk9', 'oraclejdk8'] ==  
toml.matrix.include.jdk
 
     }
+
+    // tag::typed_class[]
+    static class ServerConfig {
+        String host
+        int port
+    }
+    // end::typed_class[]
+
+    void testParseTextAs() {
+        // tag::typed_parsing[]
+        def config = new TomlSlurper().parseTextAs(ServerConfig, '''
+host = "localhost"
+port = 8080
+''')
+        assert config.host == 'localhost'
+        assert config.port == 8080
+        // end::typed_parsing[]
+    }
+
+    void testParseAsFromReader() {
+        def reader = new StringReader('host = "localhost"\nport = 8080')
+        def config = new TomlSlurper().parseAs(ServerConfig, reader)
+        assert config instanceof ServerConfig
+        assert config.host == 'localhost'
+        assert config.port == 8080
+    }
+
+    void testParseAsFromFile() {
+        def file = File.createTempFile('test', '.toml')
+        file.deleteOnExit()
+        file.text = 'host = "localhost"\nport = 9090'
+        def config = new TomlSlurper().parseAs(ServerConfig, file)
+        assert config.port == 9090
+    }
+
+    void testParseAsFromPath() {
+        def file = File.createTempFile('test', '.toml')
+        file.deleteOnExit()
+        file.text = 'host = "example.com"\nport = 443'
+        def config = new TomlSlurper().parseAs(ServerConfig, file.toPath())
+        assert config.host == 'example.com'
+    }
+
+    void testParseAsFromInputStream() {
+        def stream = new ByteArrayInputStream('host = "localhost"\nport = 
3000'.bytes)
+        def config = new TomlSlurper().parseAs(ServerConfig, stream)
+        assert config.port == 3000
+    }
 }

Reply via email to