From 10514e48cb665a973e8c9b04db577fa6fdaddf07 Mon Sep 17 00:00:00 2001 From: XIAYM-gh Date: Tue, 13 Feb 2024 18:56:10 +0800 Subject: [PATCH 1/4] Implemented custom duplicate key handling - Supports: throw an exception (by default), ignore, overwrite & merge into a JSONArray - With tests, 4/4 passed. --- .../org/json/JSONDuplicateKeyStrategy.java | 28 ++++++ src/main/java/org/json/JSONObject.java | 96 +++++++++++++++---- .../org/json/JSONParserConfiguration.java | 54 ++++++++--- .../junit/JSONObjectDuplicateKeyTest.java | 47 +++++++++ 4 files changed, 191 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/json/JSONDuplicateKeyStrategy.java create mode 100644 src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java diff --git a/src/main/java/org/json/JSONDuplicateKeyStrategy.java b/src/main/java/org/json/JSONDuplicateKeyStrategy.java new file mode 100644 index 0000000..4652dbc --- /dev/null +++ b/src/main/java/org/json/JSONDuplicateKeyStrategy.java @@ -0,0 +1,28 @@ +package org.json; + +/** + * An enum class that is supposed to be used in {@link JSONParserConfiguration}, + * it dedicates which way should be used to handle duplicate keys. + */ +public enum JSONDuplicateKeyStrategy { + /** + * The default value. And this is the way it used to be in the previous versions.
+ * The JSONParser will throw an {@link JSONException} when meet duplicate key. + */ + THROW_EXCEPTION, + + /** + * The JSONParser will ignore duplicate keys and won't overwrite the value of the key. + */ + IGNORE, + + /** + * The JSONParser will overwrite the old value of the key. + */ + OVERWRITE, + + /** + * The JSONParser will try to merge the values of the duplicate key into a {@link JSONArray}. + */ + MERGE_INTO_ARRAY +} diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 039f136..e7d5cd5 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -15,17 +15,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.ResourceBundle; -import java.util.Set; import java.util.regex.Pattern; import static org.json.NumberConversionUtil.potentialNumber; @@ -203,9 +194,28 @@ public class JSONObject { * duplicated key. */ public JSONObject(JSONTokener x) throws JSONException { + this(x, new JSONParserConfiguration()); + } + + /** + * Construct a JSONObject from a JSONTokener with custom json parse configurations. + * + * @param x + * A JSONTokener object containing the source string. + * @param jsonParserConfiguration + * Variable to pass parser custom configuration for json parsing. + * @throws JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException { this(); char c; String key; + JSONDuplicateKeyStrategy duplicateKeyStrategy = jsonParserConfiguration.getDuplicateKeyStrategy(); + + // A list to store merged keys + List mergedKeys = null; if (x.nextClean() != '{') { throw x.syntaxError("A JSONObject text must begin with '{'"); @@ -232,14 +242,45 @@ public class JSONObject { if (key != null) { // Check if key exists - if (this.opt(key) != null) { - // key already exists - throw x.syntaxError("Duplicate key \"" + key + "\""); + boolean keyExists = this.opt(key) != null; + // Read value early to make the tokener work well + Object value = null; + if (!keyExists || duplicateKeyStrategy != JSONDuplicateKeyStrategy.THROW_EXCEPTION) { + value = x.nextValue(); } - // Only add value if non-null - Object value = x.nextValue(); - if (value!=null) { - this.put(key, value); + + if (keyExists) { + switch (duplicateKeyStrategy) { + case THROW_EXCEPTION: + throw x.syntaxError("Duplicate key \"" + key + "\""); + + case MERGE_INTO_ARRAY: + if (mergedKeys == null) { + mergedKeys = new ArrayList<>(); + } + + Object current = this.get(key); + if (current instanceof JSONArray && mergedKeys.contains(key)) { + ((JSONArray) current).put(value); + break; + } + + JSONArray merged = new JSONArray(); + merged.put(current); + merged.put(value); + this.put(key, merged); + mergedKeys.add(key); + break; + } + + // == IGNORE, ignored :) + } + + if (!keyExists || duplicateKeyStrategy == JSONDuplicateKeyStrategy.OVERWRITE) { + // Only add value if non-null + if (value != null) { + this.put(key, value); + } } } @@ -294,7 +335,6 @@ public class JSONObject { /** * Construct a JSONObject from a map with recursion depth. - * */ private JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { @@ -426,7 +466,25 @@ public class JSONObject { * duplicated key. */ public JSONObject(String source) throws JSONException { - this(new JSONTokener(source)); + this(source, new JSONParserConfiguration()); + } + + /** + * Construct a JSONObject from a source JSON text string with custom json parse configurations. + * This is the most commonly used JSONObject constructor. + * + * @param source + * A string beginning with { (left + * brace) and ending with } + *  (right brace). + * @param jsonParserConfiguration + * Variable to pass parser custom configuration for json parsing. + * @exception JSONException + * If there is a syntax error in the source string or a + * duplicated key. + */ + public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + this(new JSONTokener(source), jsonParserConfiguration); } /** diff --git a/src/main/java/org/json/JSONParserConfiguration.java b/src/main/java/org/json/JSONParserConfiguration.java index f95e244..f1ea2b2 100644 --- a/src/main/java/org/json/JSONParserConfiguration.java +++ b/src/main/java/org/json/JSONParserConfiguration.java @@ -4,23 +4,47 @@ package org.json; * Configuration object for the JSON parser. The configuration is immutable. */ public class JSONParserConfiguration extends ParserConfiguration { + /** + * The way should be used to handle duplicate keys. + */ + private JSONDuplicateKeyStrategy duplicateKeyStrategy; - /** - * Configuration with the default values. - */ - public JSONParserConfiguration() { - super(); - } + /** + * Configuration with the default values. + */ + public JSONParserConfiguration() { + this(JSONDuplicateKeyStrategy.THROW_EXCEPTION); + } - @Override - protected JSONParserConfiguration clone() { - return new JSONParserConfiguration(); - } + /** + * Configure the parser with {@link JSONDuplicateKeyStrategy}. + * + * @param duplicateKeyStrategy Indicate which way should be used to handle duplicate keys. + */ + public JSONParserConfiguration(JSONDuplicateKeyStrategy duplicateKeyStrategy) { + super(); + this.duplicateKeyStrategy = duplicateKeyStrategy; + } - @SuppressWarnings("unchecked") - @Override - public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) { - return super.withMaxNestingDepth(maxNestingDepth); - } + @Override + protected JSONParserConfiguration clone() { + return new JSONParserConfiguration(); + } + @SuppressWarnings("unchecked") + @Override + public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) { + return super.withMaxNestingDepth(maxNestingDepth); + } + + public JSONParserConfiguration withDuplicateKeyStrategy(final JSONDuplicateKeyStrategy duplicateKeyStrategy) { + JSONParserConfiguration newConfig = this.clone(); + newConfig.duplicateKeyStrategy = duplicateKeyStrategy; + + return newConfig; + } + + public JSONDuplicateKeyStrategy getDuplicateKeyStrategy() { + return this.duplicateKeyStrategy; + } } diff --git a/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java b/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java new file mode 100644 index 0000000..73dc70b --- /dev/null +++ b/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java @@ -0,0 +1,47 @@ +package org.json.junit; + +import org.json.*; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class JSONObjectDuplicateKeyTest { + private static final String TEST_SOURCE = "{\"key\": \"value1\", \"key\": \"value2\", \"key\": \"value3\"}"; + + @Test(expected = JSONException.class) + public void testThrowException() { + new JSONObject(TEST_SOURCE); + } + + @Test + public void testIgnore() { + JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration( + JSONDuplicateKeyStrategy.IGNORE + )); + + assertEquals("duplicate key shouldn't be overwritten", "value1", jsonObject.getString("key")); + } + + @Test + public void testOverwrite() { + JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration( + JSONDuplicateKeyStrategy.OVERWRITE + )); + + assertEquals("duplicate key should be overwritten", "value3", jsonObject.getString("key")); + } + + @Test + public void testMergeIntoArray() { + JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration( + JSONDuplicateKeyStrategy.MERGE_INTO_ARRAY + )); + + JSONArray jsonArray; + assertTrue("duplicate key should be merged into JSONArray", jsonObject.get("key") instanceof JSONArray + && (jsonArray = jsonObject.getJSONArray("key")).length() == 3 + && jsonArray.getString(0).equals("value1") && jsonArray.getString(1).equals("value2") + && jsonArray.getString(2).equals("value3")); + } +} From 21a9fae7b042829f76e1f8ae7aab1ece66f72fb3 Mon Sep 17 00:00:00 2001 From: XIAYM-gh Date: Tue, 13 Feb 2024 22:33:30 +0800 Subject: [PATCH 2/4] Try making java 6 & old version javadoc generator compatible --- src/main/java/org/json/JSONDuplicateKeyStrategy.java | 2 +- src/main/java/org/json/JSONObject.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/json/JSONDuplicateKeyStrategy.java b/src/main/java/org/json/JSONDuplicateKeyStrategy.java index 4652dbc..954ac3a 100644 --- a/src/main/java/org/json/JSONDuplicateKeyStrategy.java +++ b/src/main/java/org/json/JSONDuplicateKeyStrategy.java @@ -6,7 +6,7 @@ package org.json; */ public enum JSONDuplicateKeyStrategy { /** - * The default value. And this is the way it used to be in the previous versions.
+ * The default value. And this is the way it used to be in the previous versions.
* The JSONParser will throw an {@link JSONException} when meet duplicate key. */ THROW_EXCEPTION, diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index e7d5cd5..1572a81 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -256,7 +256,7 @@ public class JSONObject { case MERGE_INTO_ARRAY: if (mergedKeys == null) { - mergedKeys = new ArrayList<>(); + mergedKeys = new ArrayList(); } Object current = this.get(key); From cb2c8d39629115e740fbd05d56669f44daa597e0 Mon Sep 17 00:00:00 2001 From: XIAYM-gh Date: Wed, 14 Feb 2024 17:53:58 +0800 Subject: [PATCH 3/4] Revert some unnecessary changes (mentioned in #840) --- .../org/json/JSONDuplicateKeyStrategy.java | 28 ----------- src/main/java/org/json/JSONObject.java | 46 +++---------------- .../org/json/JSONParserConfiguration.java | 24 +++++----- .../junit/JSONObjectDuplicateKeyTest.java | 30 ++---------- 4 files changed, 22 insertions(+), 106 deletions(-) delete mode 100644 src/main/java/org/json/JSONDuplicateKeyStrategy.java diff --git a/src/main/java/org/json/JSONDuplicateKeyStrategy.java b/src/main/java/org/json/JSONDuplicateKeyStrategy.java deleted file mode 100644 index 954ac3a..0000000 --- a/src/main/java/org/json/JSONDuplicateKeyStrategy.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.json; - -/** - * An enum class that is supposed to be used in {@link JSONParserConfiguration}, - * it dedicates which way should be used to handle duplicate keys. - */ -public enum JSONDuplicateKeyStrategy { - /** - * The default value. And this is the way it used to be in the previous versions.
- * The JSONParser will throw an {@link JSONException} when meet duplicate key. - */ - THROW_EXCEPTION, - - /** - * The JSONParser will ignore duplicate keys and won't overwrite the value of the key. - */ - IGNORE, - - /** - * The JSONParser will overwrite the old value of the key. - */ - OVERWRITE, - - /** - * The JSONParser will try to merge the values of the duplicate key into a {@link JSONArray}. - */ - MERGE_INTO_ARRAY -} diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 1572a81..317fd3d 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -212,10 +212,6 @@ public class JSONObject { this(); char c; String key; - JSONDuplicateKeyStrategy duplicateKeyStrategy = jsonParserConfiguration.getDuplicateKeyStrategy(); - - // A list to store merged keys - List mergedKeys = null; if (x.nextClean() != '{') { throw x.syntaxError("A JSONObject text must begin with '{'"); @@ -243,44 +239,14 @@ public class JSONObject { if (key != null) { // Check if key exists boolean keyExists = this.opt(key) != null; - // Read value early to make the tokener work well - Object value = null; - if (!keyExists || duplicateKeyStrategy != JSONDuplicateKeyStrategy.THROW_EXCEPTION) { - value = x.nextValue(); + if (keyExists && !jsonParserConfiguration.isOverwriteDuplicateKey()) { + throw x.syntaxError("Duplicate key \"" + key + "\""); } - if (keyExists) { - switch (duplicateKeyStrategy) { - case THROW_EXCEPTION: - throw x.syntaxError("Duplicate key \"" + key + "\""); - - case MERGE_INTO_ARRAY: - if (mergedKeys == null) { - mergedKeys = new ArrayList(); - } - - Object current = this.get(key); - if (current instanceof JSONArray && mergedKeys.contains(key)) { - ((JSONArray) current).put(value); - break; - } - - JSONArray merged = new JSONArray(); - merged.put(current); - merged.put(value); - this.put(key, merged); - mergedKeys.add(key); - break; - } - - // == IGNORE, ignored :) - } - - if (!keyExists || duplicateKeyStrategy == JSONDuplicateKeyStrategy.OVERWRITE) { - // Only add value if non-null - if (value != null) { - this.put(key, value); - } + Object value = x.nextValue(); + // Only add value if non-null + if (value != null) { + this.put(key, value); } } diff --git a/src/main/java/org/json/JSONParserConfiguration.java b/src/main/java/org/json/JSONParserConfiguration.java index f1ea2b2..0d8706c 100644 --- a/src/main/java/org/json/JSONParserConfiguration.java +++ b/src/main/java/org/json/JSONParserConfiguration.java @@ -5,25 +5,27 @@ package org.json; */ public class JSONParserConfiguration extends ParserConfiguration { /** - * The way should be used to handle duplicate keys. + * Used to indicate whether to overwrite duplicate key or not. */ - private JSONDuplicateKeyStrategy duplicateKeyStrategy; + private boolean overwriteDuplicateKey; /** * Configuration with the default values. */ public JSONParserConfiguration() { - this(JSONDuplicateKeyStrategy.THROW_EXCEPTION); + this(false); } /** - * Configure the parser with {@link JSONDuplicateKeyStrategy}. + * Configure the parser with argument overwriteDuplicateKey. * - * @param duplicateKeyStrategy Indicate which way should be used to handle duplicate keys. + * @param overwriteDuplicateKey Indicate whether to overwrite duplicate key or not.
+ * If not, the JSONParser will throw a {@link JSONException} + * when meeting duplicate keys. */ - public JSONParserConfiguration(JSONDuplicateKeyStrategy duplicateKeyStrategy) { + public JSONParserConfiguration(boolean overwriteDuplicateKey) { super(); - this.duplicateKeyStrategy = duplicateKeyStrategy; + this.overwriteDuplicateKey = overwriteDuplicateKey; } @Override @@ -37,14 +39,14 @@ public class JSONParserConfiguration extends ParserConfiguration { return super.withMaxNestingDepth(maxNestingDepth); } - public JSONParserConfiguration withDuplicateKeyStrategy(final JSONDuplicateKeyStrategy duplicateKeyStrategy) { + public JSONParserConfiguration withOverwriteDuplicateKey(final boolean overwriteDuplicateKey) { JSONParserConfiguration newConfig = this.clone(); - newConfig.duplicateKeyStrategy = duplicateKeyStrategy; + newConfig.overwriteDuplicateKey = overwriteDuplicateKey; return newConfig; } - public JSONDuplicateKeyStrategy getDuplicateKeyStrategy() { - return this.duplicateKeyStrategy; + public boolean isOverwriteDuplicateKey() { + return this.overwriteDuplicateKey; } } diff --git a/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java b/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java index 73dc70b..1a3525b 100644 --- a/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java +++ b/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java @@ -7,41 +7,17 @@ import static org.junit.Assert.*; import org.junit.Test; public class JSONObjectDuplicateKeyTest { - private static final String TEST_SOURCE = "{\"key\": \"value1\", \"key\": \"value2\", \"key\": \"value3\"}"; + private static final String TEST_SOURCE = "{\"key\": \"value1\", \"key\": \"value2\"}"; @Test(expected = JSONException.class) public void testThrowException() { new JSONObject(TEST_SOURCE); } - @Test - public void testIgnore() { - JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration( - JSONDuplicateKeyStrategy.IGNORE - )); - - assertEquals("duplicate key shouldn't be overwritten", "value1", jsonObject.getString("key")); - } - @Test public void testOverwrite() { - JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration( - JSONDuplicateKeyStrategy.OVERWRITE - )); + JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration(true)); - assertEquals("duplicate key should be overwritten", "value3", jsonObject.getString("key")); - } - - @Test - public void testMergeIntoArray() { - JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration( - JSONDuplicateKeyStrategy.MERGE_INTO_ARRAY - )); - - JSONArray jsonArray; - assertTrue("duplicate key should be merged into JSONArray", jsonObject.get("key") instanceof JSONArray - && (jsonArray = jsonObject.getJSONArray("key")).length() == 3 - && jsonArray.getString(0).equals("value1") && jsonArray.getString(1).equals("value2") - && jsonArray.getString(2).equals("value3")); + assertEquals("duplicate key should be overwritten", "value2", jsonObject.getString("key")); } } From af8cb376c2015ef10dfcd80d99c49c7af0e2808f Mon Sep 17 00:00:00 2001 From: XIAYM-gh Date: Mon, 19 Feb 2024 18:58:25 +0800 Subject: [PATCH 4/4] Add tests (+ fix bugs) & missing javadoc --- .../org/json/JSONParserConfiguration.java | 38 +++++++++++++--- .../java/org/json/ParserConfiguration.java | 32 ++++++------- .../junit/JSONObjectDuplicateKeyTest.java | 23 ---------- .../junit/JSONParserConfigurationTest.java | 45 +++++++++++++++++++ 4 files changed, 94 insertions(+), 44 deletions(-) delete mode 100644 src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java create mode 100644 src/test/java/org/json/junit/JSONParserConfigurationTest.java diff --git a/src/main/java/org/json/JSONParserConfiguration.java b/src/main/java/org/json/JSONParserConfiguration.java index 0d8706c..fc16f61 100644 --- a/src/main/java/org/json/JSONParserConfiguration.java +++ b/src/main/java/org/json/JSONParserConfiguration.java @@ -30,22 +30,50 @@ public class JSONParserConfiguration extends ParserConfiguration { @Override protected JSONParserConfiguration clone() { - return new JSONParserConfiguration(); + JSONParserConfiguration clone = new JSONParserConfiguration(overwriteDuplicateKey); + clone.maxNestingDepth = maxNestingDepth; + return clone; } + /** + * Defines the maximum nesting depth that the parser will descend before throwing an exception + * when parsing a map into JSONObject or parsing a {@link java.util.Collection} instance into + * JSONArray. The default max nesting depth is 512, which means the parser will throw a JsonException + * if the maximum depth is reached. + * + * @param maxNestingDepth the maximum nesting depth allowed to the JSON parser + * @return The existing configuration will not be modified. A new configuration is returned. + */ @SuppressWarnings("unchecked") @Override public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) { - return super.withMaxNestingDepth(maxNestingDepth); + JSONParserConfiguration clone = this.clone(); + clone.maxNestingDepth = maxNestingDepth; + + return clone; } + /** + * Controls the parser's behavior when meeting duplicate keys. + * If set to false, the parser will throw a JSONException when meeting a duplicate key. + * Or the duplicate key's value will be overwritten. + * + * @param overwriteDuplicateKey defines should the parser overwrite duplicate keys. + * @return The existing configuration will not be modified. A new configuration is returned. + */ public JSONParserConfiguration withOverwriteDuplicateKey(final boolean overwriteDuplicateKey) { - JSONParserConfiguration newConfig = this.clone(); - newConfig.overwriteDuplicateKey = overwriteDuplicateKey; + JSONParserConfiguration clone = this.clone(); + clone.overwriteDuplicateKey = overwriteDuplicateKey; - return newConfig; + return clone; } + /** + * The parser's behavior when meeting duplicate keys, controls whether the parser should + * overwrite duplicate keys or not. + * + * @return The overwriteDuplicateKey configuration value. + */ public boolean isOverwriteDuplicateKey() { return this.overwriteDuplicateKey; } diff --git a/src/main/java/org/json/ParserConfiguration.java b/src/main/java/org/json/ParserConfiguration.java index 5cdc10d..06cc443 100644 --- a/src/main/java/org/json/ParserConfiguration.java +++ b/src/main/java/org/json/ParserConfiguration.java @@ -20,12 +20,12 @@ public class ParserConfiguration { /** * Specifies if values should be kept as strings (true), or if - * they should try to be guessed into JSON values (numeric, boolean, string) + * they should try to be guessed into JSON values (numeric, boolean, string). */ protected boolean keepStrings; /** - * The maximum nesting depth when parsing a document. + * The maximum nesting depth when parsing an object. */ protected int maxNestingDepth; @@ -59,14 +59,14 @@ public class ParserConfiguration { // map should be cloned as well. If the values of the map are known to also // be immutable, then a shallow clone of the map is acceptable. return new ParserConfiguration( - this.keepStrings, - this.maxNestingDepth + this.keepStrings, + this.maxNestingDepth ); } /** * When parsing the XML into JSONML, specifies if values should be kept as strings (true), or if - * they should try to be guessed into JSON values (numeric, boolean, string) + * they should try to be guessed into JSON values (numeric, boolean, string). * * @return The keepStrings configuration value. */ @@ -78,22 +78,21 @@ public class ParserConfiguration { * When parsing the XML into JSONML, specifies if values should be kept as strings (true), or if * they should try to be guessed into JSON values (numeric, boolean, string) * - * @param newVal - * new value to use for the keepStrings configuration option. - * @param the type of the configuration object - * + * @param newVal new value to use for the keepStrings configuration option. + * @param the type of the configuration object * @return The existing configuration will not be modified. A new configuration is returned. */ @SuppressWarnings("unchecked") public T withKeepStrings(final boolean newVal) { - T newConfig = (T)this.clone(); + T newConfig = (T) this.clone(); newConfig.keepStrings = newVal; return newConfig; } /** * The maximum nesting depth that the parser will descend before throwing an exception - * when parsing the XML into JSONML. + * when parsing an object (e.g. Map, Collection) into JSON-related objects. + * * @return the maximum nesting depth set for this configuration */ public int getMaxNestingDepth() { @@ -102,18 +101,19 @@ public class ParserConfiguration { /** * Defines the maximum nesting depth that the parser will descend before throwing an exception - * when parsing the XML into JSONML. The default max nesting depth is 512, which means the parser - * will throw a JsonException if the maximum depth is reached. + * when parsing an object (e.g. Map, Collection) into JSON-related objects. + * The default max nesting depth is 512, which means the parser will throw a JsonException if + * the maximum depth is reached. * Using any negative value as a parameter is equivalent to setting no limit to the nesting depth, * which means the parses will go as deep as the maximum call stack size allows. + * * @param maxNestingDepth the maximum nesting depth allowed to the XML parser - * @param the type of the configuration object - * + * @param the type of the configuration object * @return The existing configuration will not be modified. A new configuration is returned. */ @SuppressWarnings("unchecked") public T withMaxNestingDepth(int maxNestingDepth) { - T newConfig = (T)this.clone(); + T newConfig = (T) this.clone(); if (maxNestingDepth > UNDEFINED_MAXIMUM_NESTING_DEPTH) { newConfig.maxNestingDepth = maxNestingDepth; diff --git a/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java b/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java deleted file mode 100644 index 1a3525b..0000000 --- a/src/test/java/org/json/junit/JSONObjectDuplicateKeyTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.json.junit; - -import org.json.*; - -import static org.junit.Assert.*; - -import org.junit.Test; - -public class JSONObjectDuplicateKeyTest { - private static final String TEST_SOURCE = "{\"key\": \"value1\", \"key\": \"value2\"}"; - - @Test(expected = JSONException.class) - public void testThrowException() { - new JSONObject(TEST_SOURCE); - } - - @Test - public void testOverwrite() { - JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration(true)); - - assertEquals("duplicate key should be overwritten", "value2", jsonObject.getString("key")); - } -} diff --git a/src/test/java/org/json/junit/JSONParserConfigurationTest.java b/src/test/java/org/json/junit/JSONParserConfigurationTest.java new file mode 100644 index 0000000..0e80d77 --- /dev/null +++ b/src/test/java/org/json/junit/JSONParserConfigurationTest.java @@ -0,0 +1,45 @@ +package org.json.junit; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONParserConfiguration; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class JSONParserConfigurationTest { + private static final String TEST_SOURCE = "{\"key\": \"value1\", \"key\": \"value2\"}"; + + @Test(expected = JSONException.class) + public void testThrowException() { + new JSONObject(TEST_SOURCE); + } + + @Test + public void testOverwrite() { + JSONObject jsonObject = new JSONObject(TEST_SOURCE, new JSONParserConfiguration(true)); + + assertEquals("duplicate key should be overwritten", "value2", jsonObject.getString("key")); + } + + @Test + public void verifyDuplicateKeyThenMaxDepth() { + JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() + .withOverwriteDuplicateKey(true) + .withMaxNestingDepth(42); + + assertEquals(42, jsonParserConfiguration.getMaxNestingDepth()); + assertTrue(jsonParserConfiguration.isOverwriteDuplicateKey()); + } + + @Test + public void verifyMaxDepthThenDuplicateKey() { + JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() + .withMaxNestingDepth(42) + .withOverwriteDuplicateKey(true); + + assertTrue(jsonParserConfiguration.isOverwriteDuplicateKey()); + assertEquals(42, jsonParserConfiguration.getMaxNestingDepth()); + } +}