Write a literal YAML field using Groovy 3.0's new YamlBuilder

1.3k Views Asked by At

Groovy 3.0 has a new YamlBuilder class that works in a similar way to the existing JsonBuilder class.

I'm trying to work out if I can use YamlBuilder to generate a literal field in YAML such as:

data: |
  this is
  a literal
  text value

My first guess was Groovy's multiline string would work:

new YamlBuilder() {
  data: '''\
this is
a literal
text value'''
}

But that gives me:

data: "this is\na literal\ntext value\n"`

I don't see anything useful in the YamlBuilder Javadoc and mrhaki's example doesn't show this use-case.

Does anyone know if/how this can be done?

2

There are 2 best solutions below

5
tim_yates On BEST ANSWER

You can do the following:

import groovy.yaml.*
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.LITERAL_BLOCK_STYLE

def yaml = new YamlBuilder()

yaml {
  data '''\
this is
a literal
text value'''
}

println new ObjectMapper(new YAMLFactory().configure(LITERAL_BLOCK_STYLE, true)).writeValueAsString(yaml)

If you need your own custom serialization

1
SteveD On

Under the covers Groovy's YamlBuilder is using Jackson's JSON to YAML converter.

Jackson's converter does support literal block style, but this needs to be enabled. The current version of YamlBuilder does not support setting options.

I copied the YamlBuilder class and the related YamlConverter class so I could modify the settings.

In the YamlBuilder class, I modified this method:

public static String convertJsonToYaml(Reader jsonReader) {
    try (Reader reader = jsonReader) {
        JsonNode json = new ObjectMapper().readTree(reader);

        return new YAMLMapper().writeValueAsString(json);
    } catch (IOException e) {
        throw new YamlRuntimeException(e);
    }
}

To be this:

public static String convertJsonToYaml(Reader jsonReader) {
    try (Reader reader = jsonReader) {
        JsonNode json = new ObjectMapper().readTree(reader);

        YAMLMapper mapper = new YAMLMapper()
        mapper.configure(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE, true)
        return mapper.writeValueAsString(json);
    } catch (IOException e) {
        throw new YamlRuntimeException(e);
    }
}

This allows me to do:

mapper.configure(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE, true)

Which will successfully render the YAML as a literal block:

data: |-
  this is
  a literal
  text value