Skip to content

Commit 097d44a

Browse files
authored
support setting snakeyaml DumperOptions explicitly (#345)
1 parent 0f7bd45 commit 097d44a

File tree

4 files changed

+223
-24
lines changed

4 files changed

+223
-24
lines changed

yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactory.java

+30-4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,26 @@ public class YAMLFactory extends JsonFactory
7878
*/
7979
protected final LoaderOptions _loaderOptions;
8080

81+
/**
82+
* Configuration for underlying generator to follow, if specified;
83+
* left as {@code null} for backwards compatibility (which means
84+
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
85+
* <p>
86+
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
87+
* <ul>
88+
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
89+
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
90+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
91+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
92+
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
93+
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
94+
* </ul>
95+
* </p>
96+
*
97+
* @since 2.14
98+
*/
99+
protected final DumperOptions _dumperOptions;
100+
81101
/*
82102
/**********************************************************************
83103
/* Factory construction, configuration
@@ -107,6 +127,7 @@ public YAMLFactory(ObjectCodec oc)
107127
_version = null;
108128
_quotingChecker = StringQuotingChecker.Default.instance();
109129
_loaderOptions = null;
130+
_dumperOptions = null;
110131
}
111132

112133
/**
@@ -120,6 +141,7 @@ public YAMLFactory(YAMLFactory src, ObjectCodec oc)
120141
_version = src._version;
121142
_quotingChecker = src._quotingChecker;
122143
_loaderOptions = src._loaderOptions;
144+
_dumperOptions = src._dumperOptions;
123145
}
124146

125147
/**
@@ -134,6 +156,7 @@ protected YAMLFactory(YAMLFactoryBuilder b)
134156
_version = b.yamlVersionToWrite();
135157
_quotingChecker = b.stringQuotingChecker();
136158
_loaderOptions = b.loaderOptions();
159+
_dumperOptions = b.dumperOptions();
137160
}
138161

139162
@Override
@@ -504,10 +527,13 @@ protected YAMLParser _createParser(byte[] data, int offset, int len, IOContext c
504527
@Override
505528
protected YAMLGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException {
506529
int feats = _yamlGeneratorFeatures;
507-
YAMLGenerator gen = new YAMLGenerator(ctxt, _generatorFeatures, feats,
508-
_quotingChecker, _objectCodec, out, _version);
509-
// any other initializations? No?
510-
return gen;
530+
if (_dumperOptions == null) {
531+
return new YAMLGenerator(ctxt, _generatorFeatures, feats,
532+
_quotingChecker, _objectCodec, out, _version);
533+
} else {
534+
return new YAMLGenerator(ctxt, _generatorFeatures, feats,
535+
_quotingChecker, _objectCodec, out, _dumperOptions);
536+
}
511537
}
512538

513539
@Override

yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLFactoryBuilder.java

+71
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public class YAMLFactoryBuilder extends TSFBuilder<YAMLFactory, YAMLFactoryBuild
3636
* YAML version for underlying generator to follow, if specified;
3737
* left as {@code null} for backwards compatibility (which means
3838
* whatever default settings {@code SnakeYAML} deems best).
39+
* <p>
40+
* Ignored if you provide your own {@code DumperOptions}.
41+
* </p>
3942
*/
4043
protected DumperOptions.Version _version;
4144

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

59+
/**
60+
* Configuration for underlying generator to follow, if specified;
61+
* left as {@code null} for backwards compatibility (which means
62+
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
63+
* <p>
64+
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
65+
* <ul>
66+
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
67+
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
68+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
69+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
70+
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
71+
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
72+
* </ul>
73+
* </p>
74+
*
75+
* @since 2.14
76+
*/
77+
protected DumperOptions _dumperOptions;
78+
5679
/*
5780
/**********************************************************
5881
/* Life cycle
@@ -164,6 +187,31 @@ public YAMLFactoryBuilder loaderOptions(LoaderOptions loaderOptions) {
164187
return this;
165188
}
166189

190+
/**
191+
* Configuration for underlying generator to follow, if specified;
192+
* left as {@code null} for backwards compatibility (which means
193+
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
194+
* <p>
195+
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
196+
* <ul>
197+
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
198+
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
199+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
200+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
201+
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
202+
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
203+
* </ul>
204+
* </p>
205+
*
206+
* @param dumperOptions the {@code SnakeYAML} configuration to use when generating YAML
207+
* @return This builder instance, to allow chaining
208+
* @since 2.14
209+
*/
210+
public YAMLFactoryBuilder dumperOptions(DumperOptions dumperOptions) {
211+
_dumperOptions = dumperOptions;
212+
return this;
213+
}
214+
167215
/*
168216
/**********************************************************
169217
/* Accessors
@@ -201,6 +249,29 @@ public LoaderOptions loaderOptions() {
201249
return _loaderOptions;
202250
}
203251

252+
/**
253+
* Configuration for underlying generator to follow, if specified;
254+
* left as {@code null} for backwards compatibility (which means
255+
* the dumper options are derived based on {@link YAMLGenerator.Feature}s).
256+
* <p>
257+
* These {@link YAMLGenerator.Feature}s are ignored if you provide your own DumperOptions:
258+
* <ul>
259+
* <li>{@code YAMLGenerator.Feature.ALLOW_LONG_KEYS}</li>
260+
* <li>{@code YAMLGenerator.Feature.CANONICAL_OUTPUT}</li>
261+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS}</li>
262+
* <li>{@code YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR}</li>
263+
* <li>{@code YAMLGenerator.Feature.SPLIT_LINES}</li>
264+
* <li>{@code YAMLGenerator.Feature.USE_PLATFORM_LINE_BREAKS}</li>
265+
* </ul>
266+
* </p>
267+
*
268+
* @return the {@code SnakeYAML} configuration to use when generating YAML
269+
* @since 2.14
270+
*/
271+
public DumperOptions dumperOptions() {
272+
return _dumperOptions;
273+
}
274+
204275
@Override
205276
public YAMLFactory build() {
206277
return new YAMLFactory(this);

yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java

+70-20
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,22 @@ public enum Feature implements FormatFeature // since 2.9
5858

5959
/**
6060
* Do we try to force so-called canonical output or not.
61+
* <p>
62+
* Ignored if you provide your own {@code DumperOptions}.
63+
* </p>
6164
*/
6265
CANONICAL_OUTPUT(false),
6366

6467
/**
6568
* Options passed to SnakeYAML that determines whether longer textual content
6669
* gets automatically split into multiple lines or not.
67-
*<p>
68-
* Feature is enabled by default to conform to SnakeYAML defaults as well as
69-
* backwards compatibility with 2.5 and earlier versions.
70+
* <p>
71+
* Feature is enabled by default to conform to SnakeYAML defaults as well as
72+
* backwards compatibility with 2.5 and earlier versions.
73+
* </p>
74+
* <p>
75+
* Ignored if you provide your own {@code DumperOptions}.
76+
* </p>
7077
*
7178
* @since 2.6
7279
*/
@@ -75,10 +82,11 @@ public enum Feature implements FormatFeature // since 2.9
7582
/**
7683
* Whether strings will be rendered without quotes (true) or
7784
* with quotes (false, default).
78-
*<p>
79-
* Minimized quote usage makes for more human readable output; however, content is
80-
* limited to printable characters according to the rules of
81-
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
85+
* <p>
86+
* Minimized quote usage makes for more human readable output; however, content is
87+
* limited to printable characters according to the rules of
88+
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
89+
* </p>
8290
*
8391
* @since 2.7
8492
*/
@@ -87,10 +95,11 @@ public enum Feature implements FormatFeature // since 2.9
8795
/**
8896
* Whether numbers stored as strings will be rendered with quotes (true) or
8997
* without quotes (false, default) when MINIMIZE_QUOTES is enabled.
90-
*<p>
91-
* Minimized quote usage makes for more human readable output; however, content is
92-
* limited to printable characters according to the rules of
93-
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
98+
* <p>
99+
* Minimized quote usage makes for more human readable output; however, content is
100+
* limited to printable characters according to the rules of
101+
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
102+
* </p>
94103
*
95104
* @since 2.8.2
96105
*/
@@ -101,8 +110,9 @@ public enum Feature implements FormatFeature // since 2.9
101110
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>
102111
* should be used. This automatically enabled when {@link #MINIMIZE_QUOTES} is set.
103112
* <p>
104-
* The content of such strings is limited to printable characters according to the rules of
105-
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
113+
* The content of such strings is limited to printable characters according to the rules of
114+
* <a href="http://www.yaml.org/spec/1.2/spec.html#style/block/literal">literal block style</a>.
115+
* </p>
106116
*
107117
* @since 2.9
108118
*/
@@ -111,17 +121,25 @@ public enum Feature implements FormatFeature // since 2.9
111121
/**
112122
* Feature enabling of which adds indentation for array entry generation
113123
* (default indentation being 2 spaces).
114-
*<p>
115-
* Default value is {@code false} for backwards compatibility
124+
* <p>
125+
* Default value is {@code false} for backwards compatibility
126+
* </p>
127+
* <p>
128+
* Ignored if you provide your own {@code DumperOptions}.
129+
* </p>
116130
*
117131
* @since 2.9
118132
*/
119133
INDENT_ARRAYS(false),
120134
/**
121135
* Feature enabling of which adds indentation with indicator for array entry generation
122136
* (default indentation being 2 spaces).
123-
*<p>
124-
* Default value is {@code false} for backwards compatibility
137+
* <p>
138+
* Default value is {@code false} for backwards compatibility
139+
* </p>
140+
* <p>
141+
* Ignored if you provide your own {@code DumperOptions}.
142+
* </p>
125143
*
126144
* @since 2.12
127145
*/
@@ -132,7 +150,11 @@ public enum Feature implements FormatFeature // since 2.9
132150
* serialization should be same as what the default is for current platform.
133151
* If disabled, Unix linefeed ({@code \n}) will be used.
134152
* <p>
135-
* Default value is {@code false} for backwards compatibility.
153+
* Default value is {@code false} for backwards compatibility
154+
* </p>
155+
* <p>
156+
* Ignored if you provide your own {@code DumperOptions}.
157+
* </p>
136158
*
137159
* @since 2.9.6
138160
*/
@@ -144,8 +166,12 @@ public enum Feature implements FormatFeature // since 2.9
144166
* If disabled, the max key length is left as 128 characters: longer names
145167
* are truncated. If enabled, limit is raised to 1024 characters.
146168
* <p>
147-
* Default value is {@code false} for backwards-compatibility (same as behavior
148-
* before this feature was added).
169+
* Default value is {@code false} for backwards-compatibility (same as behavior
170+
* before this feature was added).
171+
* </p>
172+
* <p>
173+
* Ignored if you provide your own {@code DumperOptions}.
174+
* </p>
149175
*
150176
* @since 2.14
151177
*/
@@ -283,6 +309,30 @@ public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures,
283309
_emitStartDocument();
284310
}
285311

312+
/**
313+
* @since 2.14
314+
*/
315+
public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures,
316+
StringQuotingChecker quotingChecker,
317+
ObjectCodec codec, Writer out,
318+
org.yaml.snakeyaml.DumperOptions dumperOptions)
319+
throws IOException
320+
{
321+
super(jsonFeatures, codec);
322+
_ioContext = ctxt;
323+
_formatFeatures = yamlFeatures;
324+
_quotingChecker = (quotingChecker == null)
325+
? StringQuotingChecker.Default.instance() : quotingChecker;
326+
_writer = out;
327+
_docVersion = dumperOptions.getVersion();
328+
_outputOptions = dumperOptions;
329+
330+
_emitter = new Emitter(_writer, _outputOptions);
331+
// should we start output now, or try to defer?
332+
_emit(new StreamStartEvent(null, null));
333+
_emitStartDocument();
334+
}
335+
286336
@Deprecated // since 2.12
287337
public YAMLGenerator(IOContext ctxt, int jsonFeatures, int yamlFeatures,
288338
ObjectCodec codec, Writer out,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.fasterxml.jackson.dataformat.yaml.ser;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.dataformat.yaml.ModuleTestBase;
5+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
6+
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
7+
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
8+
import org.yaml.snakeyaml.DumperOptions;
9+
10+
import static java.util.Collections.singletonList;
11+
import static java.util.Collections.singletonMap;
12+
13+
public class CustomNodeStyleTest extends ModuleTestBase {
14+
15+
private final ObjectMapper REGULAR_MAPPER = createMapper(null);
16+
private final ObjectMapper BLOCK_STYLE_MAPPER = createMapper(DumperOptions.FlowStyle.BLOCK);
17+
private final ObjectMapper FLOW_STYLE_MAPPER = createMapper(DumperOptions.FlowStyle.FLOW);
18+
19+
public void testFlowStyles() throws Exception {
20+
// list
21+
assertEquals("key_default:\n- value",
22+
_asYaml(REGULAR_MAPPER, singletonMap("key_default", singletonList("value"))));
23+
assertEquals("{key_flow: [value]}",
24+
_asYaml(FLOW_STYLE_MAPPER, singletonMap("key_flow", singletonList("value"))));
25+
assertEquals("key_block:\n- value",
26+
_asYaml(BLOCK_STYLE_MAPPER, singletonMap("key_block", singletonList("value"))));
27+
28+
// object
29+
assertEquals("key_default:\n foo: bar",
30+
_asYaml(REGULAR_MAPPER, singletonMap("key_default", singletonMap("foo", "bar"))));
31+
assertEquals("{key_flow: {foo: bar}}",
32+
_asYaml(FLOW_STYLE_MAPPER, singletonMap("key_flow", singletonMap("foo", "bar"))));
33+
assertEquals("key_block:\n foo: bar",
34+
_asYaml(BLOCK_STYLE_MAPPER, singletonMap("key_block", singletonMap("foo", "bar"))));
35+
}
36+
37+
private String _asYaml(ObjectMapper mapper, Object value) throws Exception {
38+
return mapper.writeValueAsString(value).trim();
39+
}
40+
41+
private ObjectMapper createMapper(DumperOptions.FlowStyle flowStyle) {
42+
DumperOptions dumperOptions = new DumperOptions();
43+
if (flowStyle != null) {
44+
dumperOptions.setDefaultFlowStyle(flowStyle);
45+
}
46+
YAMLFactory yamlFactory = YAMLFactory.builder().dumperOptions(dumperOptions).build();
47+
return YAMLMapper.builder(yamlFactory)
48+
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
49+
.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
50+
.build();
51+
}
52+
}

0 commit comments

Comments
 (0)