Skip to content

Commit

Permalink
FIX FasterXML#180: YAML Generator now quotes strings containing speci…
Browse files Browse the repository at this point in the history
…al chars

When using the YAMLGenerator in the MINIMIZE_QUOTES mode, the generator serializes strings in plain style, i.e. without quoting them. However, as stated in the YAML Spec [1] such plain style strings cannot contain some special characters such as ':', ',', and others.

[1] https://yaml.org/spec/1.2/spec.html#id2788859

As with the serialization of boolean-like strings, the YAMLGenerator should be adjusted to always quote strings containing those special characters.

I will shortly try to provide a pull request to fix this issue.
  • Loading branch information
trohrberg authored and Timo Rohrberg committed Mar 13, 2020
1 parent f5a1137 commit 0d3eeec
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ private Feature(boolean defaultState) {
"on", "On", "ON", "off", "Off", "OFF",
"null", "Null", "NULL"
));

/**
* As per YAML <a href="https://yaml.org/spec/1.2/spec.html#id2788859">Plain Style</a>unquoted strings are
* restriced to a reduced charset and must be quoted in case they contain one of the following characters.
*/
private final static Set<String> SPECIAL_CHARS = new HashSet<>(Arrays.asList(
":", "#", "[", "]", "{", "}", ","
));

/*
/**********************************************************
Expand Down Expand Up @@ -480,7 +488,7 @@ public void close() throws IOException
if (!isClosed()) {
// 11-Dec-2019, tatu: Should perhaps check if content is to be auto-closed...
// but need END_DOCUMENT regardless

_emitEndDocument();
_emit(new StreamEndEvent(null, null));
super.close();
Expand Down Expand Up @@ -981,6 +989,16 @@ private boolean _valueNeedsQuoting(String name) {
case 'Y': // Y/Yes/YES
return MUST_QUOTE_VALUES.contains(name);
}
return stringContainsItemFromList(name, SPECIAL_CHARS.toArray(new String[]{}));
}

private static boolean stringContainsItemFromList(String inputStr, String[] items) {
for(int i =0; i < items.length; i++) {
if (inputStr.contains( items[i] )) {
return true;
}
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,50 @@ public void testMinimizeQuotesWithNulls() throws Exception
"key: nuLL", yaml);
}

public void testMinimizeQuotesWithStringsContainingSpecialChars() throws Exception {
Map<String, Object> content = new HashMap<String, Object>();
content.put("key", "a:b");
String yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a:b\"", yaml);

content.clear();
content.put("key", "a#b");
yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a#b\"", yaml);

content.clear();
content.put("key", "a[b");
yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a[b\"", yaml);

content.clear();
content.put("key", "a]b");
yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a]b\"", yaml);

content.clear();
content.put("key", "a{b");
yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a{b\"", yaml);

content.clear();
content.put("key", "a}b");
yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a}b\"", yaml);

content.clear();
content.put("key", "a,b");
yaml = MINIM_MAPPER.writeValueAsString(content).trim();
assertEquals("---\n" +
"key: \"a,b\"", yaml);
}

public void testLiteralStringsMultiLine() throws Exception
{
Map<String, Object> content = new HashMap<String, Object>();
Expand Down

0 comments on commit 0d3eeec

Please sign in to comment.