Skip to content

Commit

Permalink
feat: add feature flag to parse boolean like words as strings (#389)
Browse files Browse the repository at this point in the history
  • Loading branch information
axelniklasson authored Feb 27, 2023
1 parent c6e5e5e commit e73ab58
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,15 @@ public enum Feature implements FormatFeature // in 2.9
* Feature is enabled by default in Jackson 2.12 for backwards-compatibility
* reasons.
*/
EMPTY_STRING_AS_NULL(true)
EMPTY_STRING_AS_NULL(true),

/**
* Feature that determines whether to parse boolean-like words as strings instead of booleans.
* When enabled, the following words will be parsed as strings instead of booleans: yes, no, on, off.
*
* @since 2.15
*/
PARSE_BOOLEAN_LIKE_WORDS_AS_STRINGS(false),
;

final boolean _defaultState;
Expand Down Expand Up @@ -633,27 +641,32 @@ protected JsonToken _decodeScalar(ScalarEvent scalar) throws IOException

protected Boolean _matchYAMLBoolean(String value, int len)
{
switch (len) {
case 1:
switch (value.charAt(0)) {
case 'y': case 'Y': return Boolean.TRUE;
case 'n': case 'N': return Boolean.FALSE;
}
break;
case 2:
if ("no".equalsIgnoreCase(value)) return Boolean.FALSE;
if ("on".equalsIgnoreCase(value)) return Boolean.TRUE;
break;
case 3:
if ("yes".equalsIgnoreCase(value)) return Boolean.TRUE;
if ("off".equalsIgnoreCase(value)) return Boolean.FALSE;
break;
case 4:
if (isEnabled(Feature.PARSE_BOOLEAN_LIKE_WORDS_AS_STRINGS)) {
if ("true".equalsIgnoreCase(value)) return Boolean.TRUE;
break;
case 5:
if ("false".equalsIgnoreCase(value)) return Boolean.FALSE;
break;
} else {
switch (len) {
case 1:
switch (value.charAt(0)) {
case 'y': case 'Y': return Boolean.TRUE;
case 'n': case 'N': return Boolean.FALSE;
}
break;
case 2:
if ("no".equalsIgnoreCase(value)) return Boolean.FALSE;
if ("on".equalsIgnoreCase(value)) return Boolean.TRUE;
break;
case 3:
if ("yes".equalsIgnoreCase(value)) return Boolean.TRUE;
if ("off".equalsIgnoreCase(value)) return Boolean.FALSE;
break;
case 4:
if ("true".equalsIgnoreCase(value)) return Boolean.TRUE;
break;
case 5:
if ("false".equalsIgnoreCase(value)) return Boolean.FALSE;
break;
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.fasterxml.jackson.dataformat.yaml.deser;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.dataformat.yaml.ModuleTestBase;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;

public class ParseBooleanLikeWordsAsStringsTest extends ModuleTestBase
{
final String YAML =
"one: Yes\n" +
"two: No\n" +
"three: Off\n" +
"four: On\n" +
"five: True\n" +
"six: False\n" +
"seven: Y\n" +
"eight: N\n";

public void testParseBooleanLikeWordsAsString_disabledFF() throws Exception
{
YAMLFactory f = new YAMLFactory();
assertFalse(f.isEnabled(YAMLParser.Feature.PARSE_BOOLEAN_LIKE_WORDS_AS_STRINGS));
ObjectMapper mapper = new ObjectMapper(f);

JsonNode root = mapper.readTree(YAML);
assertEquals(root.get("one").getNodeType(), JsonNodeType.BOOLEAN);
assertTrue(root.get("one").booleanValue());

assertEquals(root.get("two").getNodeType(), JsonNodeType.BOOLEAN);
assertFalse(root.get("two").booleanValue());

assertEquals(root.get("three").getNodeType(), JsonNodeType.BOOLEAN);
assertFalse(root.get("three").booleanValue());

assertEquals(root.get("four").getNodeType(), JsonNodeType.BOOLEAN);
assertTrue(root.get("four").booleanValue());

assertEquals(root.get("five").getNodeType(), JsonNodeType.BOOLEAN);
assertTrue(root.get("five").booleanValue());

assertEquals(root.get("six").getNodeType(), JsonNodeType.BOOLEAN);
assertFalse(root.get("six").booleanValue());

assertEquals(root.get("seven").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("seven").textValue(), "Y");

assertEquals(root.get("eight").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("eight").textValue(), "N");
}

public void testParseBooleanLikeWordsAsString_enabledFF() throws Exception
{
YAMLFactory f = new YAMLFactory().enable(YAMLParser.Feature.PARSE_BOOLEAN_LIKE_WORDS_AS_STRINGS);
assertTrue(f.isEnabled(YAMLParser.Feature.PARSE_BOOLEAN_LIKE_WORDS_AS_STRINGS));
ObjectMapper mapper = new ObjectMapper(f);

JsonNode root = mapper.readTree(YAML);
assertEquals(root.get("one").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("one").textValue(), "Yes");

assertEquals(root.get("two").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("two").textValue(), "No");

assertEquals(root.get("three").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("three").textValue(), "Off");

assertEquals(root.get("four").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("four").textValue(), "On");

assertEquals(root.get("five").getNodeType(), JsonNodeType.BOOLEAN);
assertTrue(root.get("five").booleanValue());

assertEquals(root.get("six").getNodeType(), JsonNodeType.BOOLEAN);
assertFalse(root.get("six").booleanValue());

assertEquals(root.get("seven").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("seven").textValue(), "Y");

assertEquals(root.get("eight").getNodeType(), JsonNodeType.STRING);
assertEquals(root.get("eight").textValue(), "N");
}
}

0 comments on commit e73ab58

Please sign in to comment.