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

1. YamlSlurper

YamlSlurper is a class that parses YAML 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 YAML String and recursively converts it to a list or map of objects. The other parse* methods are similar in that they return a YAML String but for different parameter types.

        def ys = new YamlSlurper()
        def yaml = ys.parseText '''
language: groovy
sudo: required
dist: trusty

matrix:
  include:
    - jdk: openjdk10
    - jdk: oraclejdk9
    - jdk: oraclejdk8

before_script:
  - |
    unset _JAVA_OPTIONS

        '''

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

Notice the result is a plain map and can be handled like a normal Groovy object instance. YamlSlurper parses the given YAML as defined by the YAML Ain’t Markup Language (YAML™).

As YamlSlurper is returning pure Groovy object instances without any special YAML classes in the back, its usage is transparent. In fact, YamlSlurper 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 YAML types and the corresponding Groovy data types:

YAML 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/time

java.lang.String (see the note below)

Whenever a value in YAML is null, YamlSlurper supplements it with the Groovy null value. This is in contrast to other YAML parsers that represent a null value with a library-provided singleton object.

For the untyped parse/parseText API, YAML date and time values are returned as String. YamlSlurper routes the untyped path through a YAML-to-JSON conversion, and JSON has no native temporal types. Use the typed parseAs/parseTextAs API (see Typed date and time values) for java.time.LocalDate, java.time.LocalTime, java.time.LocalDateTime, and java.time.OffsetDateTime fidelity.

1.1. Typed parsing

YamlSlurper can parse YAML 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 YamlSlurper().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 YamlSlurper().parseText(yaml) as ServerConfig. The parseTextAs method uses Jackson databinding, which supports richer annotation-driven mapping via @JsonProperty, @JsonFormat, etc.

1.2. Typed date and time values

When a target type declares java.time.* fields, the typed parseAs/parseTextAs API and YamlBuilder.toYaml round-trip YAML temporal values with full fidelity, including the original zone offset for OffsetDateTime:

static class Event {
    java.time.OffsetDateTime created
    java.time.LocalDate effective
    java.time.LocalTime windowStart
    java.time.LocalDateTime updated
    String name
}
def original = new Event(
        created: java.time.OffsetDateTime.parse('1979-05-27T07:32:00-08:00'),
        effective: java.time.LocalDate.of(1979, 5, 27),
        windowStart: java.time.LocalTime.of(7, 32, 0),
        updated: java.time.LocalDateTime.of(1979, 5, 27, 7, 32, 0),
        name: 'demo')

def yaml = YamlBuilder.toYaml(original)
def parsed = new YamlSlurper().parseTextAs(Event, yaml)

assert parsed.created == original.created            // OffsetDateTime, non-UTC offset preserved
assert parsed.effective == original.effective        // LocalDate
assert parsed.windowStart == original.windowStart    // LocalTime
assert parsed.updated == original.updated            // LocalDateTime
assert parsed.name == original.name

1.3. Builders

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

        def builder = new YamlBuilder()
        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"
    make: "Holden"
    year: 2006
    country: "Australia"
    homepage: "http://example.org"
    record:
      type: "speed"
      description: "production pickup truck with speed of 271kph"
'''

1.4. Typed writing

YamlBuilder.toYaml(object) serializes a typed object directly to YAML using Jackson databinding:

static class ServerConfig {
    String host
    int port
}

@Test
void testToYaml() {
    def config = new ServerConfig(host: 'localhost', port: 8080)
    def yaml = YamlBuilder.toYaml(config)
    assert yaml.contains('host:')
    assert yaml.contains('localhost')
    assert yaml.contains('port:')
    assert yaml.contains('8080')
}