feat(#871-strictMode): add allowSingleQuote option, add enhancements and simplification

This commit is contained in:
rikkarth 2024-03-30 11:06:30 +00:00
parent d2cb38dba7
commit c0918c2428
No known key found for this signature in database
GPG Key ID: 11E5F28B0AED6AC7
5 changed files with 58 additions and 30 deletions

View File

@ -113,11 +113,7 @@ public class JSONArray implements Iterable<Object> {
this.myArrayList.add(JSONObject.NULL);
} else {
x.back();
if (jsonParserConfiguration.isStrictMode()) {
this.myArrayList.add(x.nextValue(true));
} else {
this.myArrayList.add(x.nextValue());
}
this.myArrayList.add(x.nextValue(jsonParserConfiguration));
}
switch (x.nextClean()) {
case 0:

View File

@ -225,7 +225,7 @@ public class JSONObject {
case '}':
return;
default:
key = x.nextSimpleValue(c, jsonParserConfiguration.isStrictMode()).toString();
key = x.nextSimpleValue(c, jsonParserConfiguration).toString();
}
// The key is followed by ':'.
@ -244,7 +244,7 @@ public class JSONObject {
throw x.syntaxError("Duplicate key \"" + key + "\"");
}
Object value = getValue(x, jsonParserConfiguration.isStrictMode());
Object value = x.nextValue(jsonParserConfiguration);
// Only add value if non-null
if (value != null) {
this.put(key, value);
@ -272,12 +272,6 @@ public class JSONObject {
}
}
private Object getValue(JSONTokener x, boolean strictMode) {
if (strictMode) {
return x.nextValue(true);
}
return x.nextValue();
}
/**
* Construct a JSONObject from a Map.
*

View File

@ -25,6 +25,11 @@ public class JSONParserConfiguration extends ParserConfiguration {
*/
private boolean strictMode;
/**
* Allows Single Quotes when strictMode is true. Has no effect if strictMode is false.
*/
private boolean allowSingleQuotes;
/**
* Configuration with the default values.
*/
@ -92,6 +97,24 @@ public class JSONParserConfiguration extends ParserConfiguration {
return clone;
}
/**
* Allows single quotes mode configuration for JSON parser when strictMode is on.
* <p>
* If this option is set to true when strict Mode is enabled, the parser will allow single quoted fields.
* <p>
* This option is false by default.
*
* @param mode a boolean value indicating whether single quotes should be allowed or not
* @return a new JSONParserConfiguration instance with the updated strict mode setting
*/
public JSONParserConfiguration allowSingleQuotes(final boolean mode) {
JSONParserConfiguration clone = this.clone();
clone.strictMode = this.strictMode;
clone.allowSingleQuotes = mode;
return clone;
}
/**
* The parser's behavior when meeting duplicate keys, controls whether the parser should
* overwrite duplicate keys or not.
@ -115,4 +138,14 @@ public class JSONParserConfiguration extends ParserConfiguration {
public boolean isStrictMode() {
return this.strictMode;
}
/**
* Retrieves the allow single quotes option.
* <p>
* Allow Single Quotes, when enabled during strict mode, instructs the parser to allow single quoted JSON fields.
* The parser will not throw a JSONException if compliant single quoted fields are found in the JSON structure.
*
* @return the current allow single quotes setting.
*/
public boolean isAllowSingleQuotes() {return this.allowSingleQuotes;}
}

View File

@ -412,29 +412,29 @@ public class JSONTokener {
* @throws JSONException If syntax error.
*/
public Object nextValue() throws JSONException {
return nextValue(false);
return nextValue(new JSONParserConfiguration());
}
/**
* Get the next value. The value can be a Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
* JSONObject.NULL object. The strictMode parameter controls the behavior of the method when parsing the value.
*
* @param strictMode If true, the method will strictly adhere to the JSON syntax, throwing a JSONException for any
* deviations.
* @param jsonParserConfiguration which carries options such as strictMode and allowSingleQuotes, these methods will
* strictly adhere to the JSON syntax, throwing a JSONException for any deviations.
* @return An object.
* @throws JSONException If syntax error.
*/
public Object nextValue(boolean strictMode) throws JSONException {
public Object nextValue(JSONParserConfiguration jsonParserConfiguration) throws JSONException {
char c = this.nextClean();
switch (c) {
case '{':
this.back();
return getJsonObject(strictMode);
return getJsonObject(jsonParserConfiguration);
case '[':
this.back();
return getJsonArray();
default:
return nextSimpleValue(c, strictMode);
return nextSimpleValue(c, jsonParserConfiguration);
}
}
@ -442,18 +442,15 @@ public class JSONTokener {
* This method is used to get a JSONObject from the JSONTokener. The strictMode parameter controls the behavior of
* the method when parsing the JSONObject.
*
* @param strictMode If true, the method will strictly adhere to the JSON syntax, throwing a JSONException for any
* @param jsonParserConfiguration which carries options such as strictMode and allowSingleQuotes, these methods will
* strictly adhere to the JSON syntax, throwing a JSONException for any deviations.
* deviations.
* @return A JSONObject which is the next value in the JSONTokener.
* @throws JSONException If the JSONObject or JSONArray depth is too large to process.
*/
private JSONObject getJsonObject(boolean strictMode) {
private JSONObject getJsonObject(JSONParserConfiguration jsonParserConfiguration) {
try {
if (strictMode) {
return new JSONObject(this, new JSONParserConfiguration().withStrictMode(true));
}
return new JSONObject(this);
return new JSONObject(this, jsonParserConfiguration);
} catch (StackOverflowError e) {
throw new JSONException("JSON Array or Object depth too large to process.", e);
}
@ -473,7 +470,14 @@ public class JSONTokener {
}
}
Object nextSimpleValue(char c, boolean strictMode) {
Object nextSimpleValue(char c, JSONParserConfiguration jsonParserConfiguration) {
boolean strictMode = jsonParserConfiguration.isStrictMode();
boolean allowSingleQuotes = jsonParserConfiguration.isAllowSingleQuotes();
if(strictMode && !allowSingleQuotes && c == '\''){
throw this.syntaxError("Single quote wrap not allowed in strict mode");
}
if (c == '"' || c == '\'') {
return this.nextString(c, strictMode);
}

View File

@ -118,9 +118,9 @@ public class JSONParserConfigurationTest {
}
@Test
public void givenUnbalancedQuotes_testStrictModeTrue_shouldThrowJsonExceptionWtihConcreteErrorDescription() {
public void givenUnbalancedQuotes_testStrictModeTrueAndAllowSingleQuotes_shouldThrowJsonExceptionWtihConcreteErrorDescription() {
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration()
.withStrictMode(true);
.withStrictMode(true).allowSingleQuotes(true);
String testCaseOne = "[\"abc', \"test\"]";
String testCaseTwo = "['abc\", \"test\"]";
@ -198,6 +198,7 @@ public class JSONParserConfigurationTest {
return Arrays.asList(
"[1,2];[3,4]",
"[test]",
"[{'testSingleQuote': 'testSingleQuote'}]",
"[1, 2,3]:[4,5]",
"[{test: implied}]",
"[{\"test\": implied}]",