Groovy has an optional groovy-toml module which provides support for converting between Groovy objects and TOML. The classes dedicated to TOML serialization and parsing are found in the groovy.toml package.

1. TomlSlurper

TomlSlurper is a class that parses TOML text or reader content into Groovy data structures (objects) such as maps, lists and primitive types like Integer, Double, Boolean and String.

The class comes with a bunch of overloaded parse methods plus some special methods such as parseText and others. For the next example we will use the parseText method. It parses a TOML String and recursively converts it to a list or map of objects. The other parse* methods are similar in that they return a TOML String but for different parameter types.

        def ts = new TomlSlurper()
        def toml = ts.parseText '''
language = "groovy"
sudo = "required"
dist = "trusty"
before_script = [ "unset _JAVA_OPTIONS\\n\\n    \\n" ]

[[matrix.include]]
jdk = "openjdk10"

[[matrix.include]]
jdk = "oraclejdk9"

[[matrix.include]]
jdk = "oraclejdk8"
'''

        assert 'groovy' == toml.language
        assert 'required' == toml.sudo
        assert 'trusty' == toml.dist
        assert ['openjdk10', 'oraclejdk9', 'oraclejdk8'] ==  toml.matrix.include.jdk
        assert ['unset _JAVA_OPTIONS'] == toml.before_script*.trim()

Notice the result is a plain map and can be handled like a normal Groovy object instance. TomlSlurper parses the given TOML as defined by the Tom’s Obvious, Minimal Language.

As TomlSlurper is returning pure Groovy object instances without any special TOML classes in the back, its usage is transparent. In fact, TomlSlurper results conform to GPath expressions. GPath is a powerful expression language that is supported by multiple slurpers for different data formats (XmlSlurper for XML being one example).

For more details please have a look at the section on GPath expressions.

The following table gives an overview of the TOML types and the corresponding Groovy data types:

TOML Groovy

string

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 based on the yyyy-MM-dd’T’HH:mm:ssZ date format

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.

1.1. 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:

static class ServerConfig {
    String host
    int port
}
        def config = new TomlSlurper().parseTextAs(ServerConfig, '''
host = "localhost"
port = 8080
''')
        assert config.host == 'localhost'
        assert config.port == 8080
For simple cases, Groovy’s as coercion also works with the untyped result: def config = new TomlSlurper().parseText(toml) as ServerConfig. The parseTextAs method uses Jackson databinding, which supports richer annotation-driven mapping via @JsonProperty, @JsonFormat, etc.

1.2. Builders

Another way to create TOML from Groovy is to use TomlBuilder. The builder provide a DSL which allows to formulate an object graph which is then converted to TOML.

        def builder = new TomlBuilder()
        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 builder.toString() == '''\
records.car.name = 'HSV Maloo'
records.car.make = 'Holden'
records.car.year = 2006
records.car.country = 'Australia'
records.car.homepage = 'http://example.org'
records.car.record.type = 'speed'
records.car.record.description = 'production pickup truck with speed of 271kph'
'''

1.3. Typed writing

TomlBuilder.toToml(object) serializes a typed object directly to TOML using Jackson databinding:

static class ServerConfig {
    String host
    int port
}

@Test
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')
}