Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configuring SnakeYAML DumperOptions directly #345

Merged
merged 3 commits into from
Sep 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,26 @@ public class YAMLFactory extends JsonFactory
*/
protected final LoaderOptions _loaderOptions;

/**
* Configuration for underlying generator to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
* <p>
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
* <ul>
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
* </ul>
* </p>
*
* @since 2.14
*/
protected final DumperOptions _dumperOptions;

/*
/**********************************************************************
/* Factory construction, configuration
Expand Down Expand Up @@ -107,6 +127,7 @@ public YAMLFactory(ObjectCodec oc)
_version = null;
_quotingChecker = StringQuotingChecker.Default.instance();
_loaderOptions = null;
_dumperOptions = null;
}

/**
Expand All @@ -120,6 +141,7 @@ public YAMLFactory(YAMLFactory src, ObjectCodec oc)
_version = src._version;
_quotingChecker = src._quotingChecker;
_loaderOptions = src._loaderOptions;
_dumperOptions = src._dumperOptions;
}

/**
Expand All @@ -134,6 +156,7 @@ protected YAMLFactory(YAMLFactoryBuilder b)
_version = b.yamlVersionToWrite();
_quotingChecker = b.stringQuotingChecker();
_loaderOptions = b.loaderOptions();
_dumperOptions = b.dumperOptions();
}

@Override
Expand Down Expand Up @@ -504,10 +527,13 @@ protected YAMLParser _createParser(byte[] data, int offset, int len, IOContext c
@Override
protected YAMLGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException {
int feats = _yamlGeneratorFeatures;
YAMLGenerator gen = new YAMLGenerator(ctxt, _generatorFeatures, feats,
_quotingChecker, _objectCodec, out, _version);
// any other initializations? No?
return gen;
if (_dumperOptions == null) {
return new YAMLGenerator(ctxt, _generatorFeatures, feats,
_quotingChecker, _objectCodec, out, _version);
} else {
return new YAMLGenerator(ctxt, _generatorFeatures, feats,
_quotingChecker, _objectCodec, out, _dumperOptions);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public class YAMLFactoryBuilder extends TSFBuilder<YAMLFactory, YAMLFactoryBuild
* YAML version for underlying generator to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* whatever default settings {@code SnakeYAML} deems best).
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*/
protected DumperOptions.Version _version;

Expand All @@ -53,6 +56,26 @@ public class YAMLFactoryBuilder extends TSFBuilder<YAMLFactory, YAMLFactoryBuild
*/
protected LoaderOptions _loaderOptions;

/**
* Configuration for underlying generator to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
* <p>
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
* <ul>
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
* </ul>
* </p>
*
* @since 2.14
*/
protected DumperOptions _dumperOptions;

/*
/**********************************************************
/* Life cycle
Expand Down Expand Up @@ -164,6 +187,31 @@ public YAMLFactoryBuilder loaderOptions(LoaderOptions loaderOptions) {
return this;
}

/**
* Configuration for underlying generator to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
* <p>
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
* <ul>
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
* </ul>
* </p>
*
* @param dumperOptions the {@code SnakeYAML} configuration to use when generating YAML
* @return This builder instance, to allow chaining
* @since 2.14
*/
public YAMLFactoryBuilder dumperOptions(DumperOptions dumperOptions) {
_dumperOptions = dumperOptions;
return this;
}

/*
/**********************************************************
/* Accessors
Expand Down Expand Up @@ -201,6 +249,29 @@ public LoaderOptions loaderOptions() {
return _loaderOptions;
}

/**
* Configuration for underlying generator to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
* <p>
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
* <ul>
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
* </ul>
* </p>
*
* @return the {@code SnakeYAML} configuration to use when generating YAML
* @since 2.14
*/
public DumperOptions dumperOptions() {
return _dumperOptions;
}

@Override
public YAMLFactory build() {
return new YAMLFactory(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,22 @@ public enum Feature implements FormatFeature // since 2.9

/**
* Do we try to force so-called canonical output or not.
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*/
CANONICAL_OUTPUT(false),

/**
* Options passed to SnakeYAML that determines whether longer textual content
* gets automatically split into multiple lines or not.
*<p>
* Feature is enabled by default to conform to SnakeYAML defaults as well as
* backwards compatibility with 2.5 and earlier versions.
* <p>
* Feature is enabled by default to conform to SnakeYAML defaults as well as
* backwards compatibility with 2.5 and earlier versions.
* </p>
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*
* @since 2.6
*/
Expand All @@ -75,10 +82,11 @@ public enum Feature implements FormatFeature // since 2.9
/**
* Whether strings will be rendered without quotes (true) or
* with quotes (false, default).
*<p>
* Minimized quote usage makes for more human readable output; however, content is
* limited to printable characters according to the rules of
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
* <p>
* Minimized quote usage makes for more human readable output; however, content is
* limited to printable characters according to the rules of
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
* </p>
*
* @since 2.7
*/
Expand All @@ -87,10 +95,11 @@ public enum Feature implements FormatFeature // since 2.9
/**
* Whether numbers stored as strings will be rendered with quotes (true) or
* without quotes (false, default) when MINIMIZE_QUOTES is enabled.
*<p>
* Minimized quote usage makes for more human readable output; however, content is
* limited to printable characters according to the rules of
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
* <p>
* Minimized quote usage makes for more human readable output; however, content is
* limited to printable characters according to the rules of
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
* </p>
*
* @since 2.8.2
*/
Expand All @@ -101,8 +110,9 @@ public enum Feature implements FormatFeature // since 2.9
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>
* should be used. This automatically enabled when {@link #MINIMIZE_QUOTES} is set.
* <p>
* The content of such strings is limited to printable characters according to the rules of
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
* The content of such strings is limited to printable characters according to the rules of
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
* </p>
*
* @since 2.9
*/
Expand All @@ -111,17 +121,25 @@ public enum Feature implements FormatFeature // since 2.9
/**
* Feature enabling of which adds indentation for array entry generation
* (default indentation being 2 spaces).
*<p>
* Default value is {@code false} for backwards compatibility
* <p>
* Default value is {@code false} for backwards compatibility
* </p>
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*
* @since 2.9
*/
INDENT_ARRAYS(false),
/**
* Feature enabling of which adds indentation with indicator for array entry generation
* (default indentation being 2 spaces).
*<p>
* Default value is {@code false} for backwards compatibility
* <p>
* Default value is {@code false} for backwards compatibility
* </p>
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*
* @since 2.12
*/
Expand All @@ -132,7 +150,11 @@ public enum Feature implements FormatFeature // since 2.9
* serialization should be same as what the default is for current platform.
* If disabled, Unix linefeed ({@code \n}) will be used.
* <p>
* Default value is {@code false} for backwards compatibility.
* Default value is {@code false} for backwards compatibility
* </p>
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*
* @since 2.9.6
*/
Expand All @@ -144,8 +166,12 @@ public enum Feature implements FormatFeature // since 2.9
* If disabled, the max key length is left as 128 characters: longer names
* are truncated. If enabled, limit is raised to 1024 characters.
* <p>
* Default value is {@code false} for backwards-compatibility (same as behavior
* before this feature was added).
* Default value is {@code false} for backwards-compatibility (same as behavior
* before this feature was added).
* </p>
* <p>
* Ignored if you provide your own {@code DumperOptions}.
* </p>
*
* @since 2.14
*/
Expand Down Expand Up @@ -283,6 +309,30 @@ public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures,
_emitStartDocument();
}

/**
* @since 2.14
*/
public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures,
StringQuotingChecker quotingChecker,
ObjectCodec codec, Writer out,
org.yaml.snakeyaml.DumperOptions dumperOptions)
throws IOException
{
super(jsonFeatures, codec);
_ioContext = ctxt;
_formatFeatures = yamlFeatures;
_quotingChecker = (quotingChecker == null)
? StringQuotingChecker.Default.instance() : quotingChecker;
_writer = out;
_docVersion = dumperOptions.getVersion();
_outputOptions = dumperOptions;

_emitter = new Emitter(_writer, _outputOptions);
// should we start output now, or try to defer?
_emit(new StreamStartEvent(null, null));
_emitStartDocument();
}

@Deprecated // since 2.12
public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures,
ObjectCodec codec, Writer out,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.fasterxml.jackson.dataformat.yaml.ser;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.ModuleTestBase;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import org.yaml.snakeyaml.DumperOptions;

import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;

public class CustomNodeStyleTest extends ModuleTestBase {

private final ObjectMapper REGULAR_MAPPER = createMapper(null);
private final ObjectMapper BLOCK_STYLE_MAPPER = createMapper(DumperOptions.FlowStyle.BLOCK);
private final ObjectMapper FLOW_STYLE_MAPPER = createMapper(DumperOptions.FlowStyle.FLOW);

public void testFlowStyles() throws Exception {
// list
assertEquals("key_default:\n- value",
_asYaml(REGULAR_MAPPER, singletonMap("key_default", singletonList("value"))));
assertEquals("{key_flow: [value]}",
_asYaml(FLOW_STYLE_MAPPER, singletonMap("key_flow", singletonList("value"))));
assertEquals("key_block:\n- value",
_asYaml(BLOCK_STYLE_MAPPER, singletonMap("key_block", singletonList("value"))));

// object
assertEquals("key_default:\n foo: bar",
_asYaml(REGULAR_MAPPER, singletonMap("key_default", singletonMap("foo", "bar"))));
assertEquals("{key_flow: {foo: bar}}",
_asYaml(FLOW_STYLE_MAPPER, singletonMap("key_flow", singletonMap("foo", "bar"))));
assertEquals("key_block:\n foo: bar",
_asYaml(BLOCK_STYLE_MAPPER, singletonMap("key_block", singletonMap("foo", "bar"))));
}

private String _asYaml(ObjectMapper mapper, Object value) throws Exception {
return mapper.writeValueAsString(value).trim();
}

private ObjectMapper createMapper(DumperOptions.FlowStyle flowStyle) {
DumperOptions dumperOptions = new DumperOptions();
if (flowStyle != null) {
dumperOptions.setDefaultFlowStyle(flowStyle);
}
YAMLFactory yamlFactory = YAMLFactory.builder().dumperOptions(dumperOptions).build();
return YAMLMapper.builder(yamlFactory)
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
.build();
}
}