From 4cb291cab2a0806a75f3fa2b9add15b5a0d7261a Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Tue, 25 Aug 2020 18:40:16 +0100 Subject: [PATCH 1/9] Fix double escape() when parsing and querying JSON Pointers. Note that JSONPointer escape()s each ref on construction, and again during queryFrom when accessing values up on the queried document. This causes queries involving keys that contain two backslashes; //. I believe that the test quotationEscaping() is currently enforcing incorrect behavior. --- src/main/java/org/json/JSONPointer.java | 2 +- .../java/org/json/junit/JSONPointerTest.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/json/JSONPointer.java b/src/main/java/org/json/JSONPointer.java index e8a0b78c9..7e4a4de3e 100644 --- a/src/main/java/org/json/JSONPointer.java +++ b/src/main/java/org/json/JSONPointer.java @@ -210,7 +210,7 @@ public Object queryFrom(Object document) throws JSONPointerException { Object current = document; for (String token : this.refTokens) { if (current instanceof JSONObject) { - current = ((JSONObject) current).opt(unescape(token)); + current = ((JSONObject) current).opt(token); } else if (current instanceof JSONArray) { current = readByIndexToken(current, token); } else { diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index e06851eb7..37384ed02 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -124,7 +124,7 @@ public void backslashEscaping() { @Test public void quotationEscaping() { - assertSame(document.get("k\"l"), query("/k\\\\\\\"l")); + assertSame(document.get("k\"l"), query("/k\\\"l")); } @Test @@ -276,6 +276,20 @@ public void queryFromJSONObjectUsingPointer() { } } + /** + * Coverage for JSONObject query(JSONPointer) + */ + @Test + public void queryFromJSONObjectUsingPointer2() { + String str = "{"+ + "\"string\\\\\\\\Key\":\"hello world!\","+ + "}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + Object obj = jsonObject.query(new JSONPointer("/string\\\\\\\\Key")); + assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); + } + /** * Coverage for JSONObject optQuery(JSONPointer) */ From 47be1a6522eae02361427047c895203c491860ae Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Tue, 25 Aug 2020 19:19:47 +0100 Subject: [PATCH 2/9] Revert "Fix double escape() when parsing and querying JSON Pointers." This reverts commit 4cb291cab2a0806a75f3fa2b9add15b5a0d7261a. --- src/main/java/org/json/JSONPointer.java | 2 +- .../java/org/json/junit/JSONPointerTest.java | 16 +--------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/json/JSONPointer.java b/src/main/java/org/json/JSONPointer.java index 7e4a4de3e..e8a0b78c9 100644 --- a/src/main/java/org/json/JSONPointer.java +++ b/src/main/java/org/json/JSONPointer.java @@ -210,7 +210,7 @@ public Object queryFrom(Object document) throws JSONPointerException { Object current = document; for (String token : this.refTokens) { if (current instanceof JSONObject) { - current = ((JSONObject) current).opt(token); + current = ((JSONObject) current).opt(unescape(token)); } else if (current instanceof JSONArray) { current = readByIndexToken(current, token); } else { diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index 37384ed02..e06851eb7 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -124,7 +124,7 @@ public void backslashEscaping() { @Test public void quotationEscaping() { - assertSame(document.get("k\"l"), query("/k\\\"l")); + assertSame(document.get("k\"l"), query("/k\\\\\\\"l")); } @Test @@ -276,20 +276,6 @@ public void queryFromJSONObjectUsingPointer() { } } - /** - * Coverage for JSONObject query(JSONPointer) - */ - @Test - public void queryFromJSONObjectUsingPointer2() { - String str = "{"+ - "\"string\\\\\\\\Key\":\"hello world!\","+ - "}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - Object obj = jsonObject.query(new JSONPointer("/string\\\\\\\\Key")); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - } - /** * Coverage for JSONObject optQuery(JSONPointer) */ From 8d6e1d85ff581e0934b839df04554b10f6f9ab29 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Tue, 25 Aug 2020 19:22:06 +0100 Subject: [PATCH 3/9] Fix double unescape() when parsing and querying JSON Pointers. It seems that JSONPointer unescape()s each ref on construction, and again during queryFrom when accessing values up on the queried document. This causes queries to fail that involve keys that contain four backslashes; \\\\. It is quite possible other rare sequences will also have problems. I believe that the test quotationEscaping() is currently enforcing incorrect behavior, so I have changed that. --- src/main/java/org/json/JSONPointer.java | 2 +- .../java/org/json/junit/JSONPointerTest.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/json/JSONPointer.java b/src/main/java/org/json/JSONPointer.java index e8a0b78c9..7e4a4de3e 100644 --- a/src/main/java/org/json/JSONPointer.java +++ b/src/main/java/org/json/JSONPointer.java @@ -210,7 +210,7 @@ public Object queryFrom(Object document) throws JSONPointerException { Object current = document; for (String token : this.refTokens) { if (current instanceof JSONObject) { - current = ((JSONObject) current).opt(unescape(token)); + current = ((JSONObject) current).opt(token); } else if (current instanceof JSONArray) { current = readByIndexToken(current, token); } else { diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index e06851eb7..37384ed02 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -124,7 +124,7 @@ public void backslashEscaping() { @Test public void quotationEscaping() { - assertSame(document.get("k\"l"), query("/k\\\\\\\"l")); + assertSame(document.get("k\"l"), query("/k\\\"l")); } @Test @@ -276,6 +276,20 @@ public void queryFromJSONObjectUsingPointer() { } } + /** + * Coverage for JSONObject query(JSONPointer) + */ + @Test + public void queryFromJSONObjectUsingPointer2() { + String str = "{"+ + "\"string\\\\\\\\Key\":\"hello world!\","+ + "}"+ + "}"; + JSONObject jsonObject = new JSONObject(str); + Object obj = jsonObject.query(new JSONPointer("/string\\\\\\\\Key")); + assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); + } + /** * Coverage for JSONObject optQuery(JSONPointer) */ From 041808c1501e64073883025a58b814701174745b Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Sun, 6 Sep 2020 11:34:36 +0100 Subject: [PATCH 4/9] Null is valid in JSON Arrays. --- src/main/java/org/json/JSONArray.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java index f11b328d8..9160aef01 100644 --- a/src/main/java/org/json/JSONArray.java +++ b/src/main/java/org/json/JSONArray.java @@ -259,11 +259,10 @@ public Iterator iterator() { * If there is no value for the index. */ public Object get(int index) throws JSONException { - Object object = this.opt(index); - if (object == null) { + if (index < 0 || index >= length()) { throw new JSONException("JSONArray[" + index + "] not found."); } - return object; + return this.opt(index); } /** From 13eff2397718f9446c52e6a84d714ba4c67a0622 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Sun, 6 Sep 2020 18:31:28 +0100 Subject: [PATCH 5/9] Nulls OK in objects. --- src/main/java/org/json/JSONObject.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index f718c0618..a14a8c6a9 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -1819,12 +1819,10 @@ public JSONObject put(String key, Object value) throws JSONException { if (key == null) { throw new NullPointerException("Null key."); } - if (value != null) { - testValidity(value); - this.map.put(key, value); - } else { - this.remove(key); - } + + testValidity(value); + + this.map.put(key, value); return this; } From 9af4d030ce14172c8195077d2f68d2d02e0c56cc Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Tue, 22 Sep 2020 11:06:10 +0100 Subject: [PATCH 6/9] Ordered map for aesthetics. --- src/main/java/org/json/JSONObject.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index a14a8c6a9..31c3e0e6e 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -40,6 +40,7 @@ of this software and associated documentation files (the "Software"), to deal import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; @@ -175,13 +176,8 @@ public String toString() { * Construct an empty JSONObject. */ public JSONObject() { - // HashMap is used on purpose to ensure that elements are unordered by - // the specification. - // JSON tends to be a portable transfer format to allows the container - // implementations to rearrange their items for a faster element - // retrieval based on associative access. - // Therefore, an implementation mustn't rely on the order of the item. - this.map = new HashMap(); + // Ordered hashmap for aesthetics. + this.map = new LinkedHashMap<>(); } /** From b741cc4b11bb56b9abda75c0757f339f34242e74 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Sat, 17 Oct 2020 19:32:58 +0100 Subject: [PATCH 7/9] Remove validity checks. --- src/main/java/org/json/JSONObject.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 31c3e0e6e..65f87919b 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -2210,19 +2210,7 @@ public static Object stringToValue(String string) { * If o is a non-finite number. */ public static void testValidity(Object o) throws JSONException { - if (o != null) { - if (o instanceof Double) { - if (((Double) o).isInfinite() || ((Double) o).isNaN()) { - throw new JSONException( - "JSON does not allow non-finite numbers."); - } - } else if (o instanceof Float) { - if (((Float) o).isInfinite() || ((Float) o).isNaN()) { - throw new JSONException( - "JSON does not allow non-finite numbers."); - } - } - } + } /** From 7a3ab875a865c18d17eac904e7c4e705617c4d01 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Mon, 19 Oct 2020 22:16:43 +0100 Subject: [PATCH 8/9] Remove validity checks. --- src/main/java/org/json/JSONObject.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 65f87919b..001c54439 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -38,7 +38,6 @@ of this software and associated documentation files (the "Software"), to deal import java.math.BigInteger; import java.util.Collection; import java.util.Enumeration; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Locale; @@ -282,9 +281,9 @@ public JSONObject(JSONTokener x) throws JSONException { */ public JSONObject(Map m) { if (m == null) { - this.map = new HashMap(); + this.map = new LinkedHashMap(); } else { - this.map = new HashMap(m.size()); + this.map = new LinkedHashMap(m.size()); for (final Entry e : m.entrySet()) { if(e.getKey() == null) { throw new NullPointerException("Null key."); @@ -453,7 +452,7 @@ public JSONObject(String baseName, Locale locale) throws JSONException { * @param initialCapacity initial capacity of the internal map. */ protected JSONObject(int initialCapacity){ - this.map = new HashMap(initialCapacity); + this.map = new LinkedHashMap(initialCapacity); } /** @@ -2531,7 +2530,7 @@ public Writer write(Writer writer, int indentFactor, int indent) * @return a java.util.Map containing the entries of this object */ public Map toMap() { - Map results = new HashMap(); + Map results = new LinkedHashMap(); for (Entry entry : this.entrySet()) { Object value; if (entry.getValue() == null || NULL.equals(entry.getValue())) { From 8373161e7c6fa688d7b01d58874d6c89836d4b71 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Mon, 19 Oct 2020 22:46:29 +0100 Subject: [PATCH 9/9] Null values OK. --- src/main/java/org/json/JSONObject.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 001c54439..a8e54209a 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -289,9 +289,9 @@ public JSONObject(Map m) { throw new NullPointerException("Null key."); } final Object value = e.getValue(); - if (value != null) { + this.map.put(String.valueOf(e.getKey()), wrap(value)); - } + } } }