20 Commits

Author SHA1 Message Date
Sean Leary
7299b201f4 Update pom.xml 2021-03-07 21:11:48 -06:00
Sean Leary
8cc1e9830d Update README.md 2021-03-07 21:09:01 -06:00
Sean Leary
c43e21ae73 Merge pull request #588 from fossterer/563-jsonpointer-do-not-encode-quotes
JSONPointer should not process reverse solidus or double-quote chars in tokens
2021-03-06 10:00:32 -06:00
Shashank Sabniveesu
d6ccc64c79 Closes 563: As never defined in RFC 6901 Section 3, do not handle backslashes (\) and quotes(") as anything special 2021-02-28 16:03:14 -05:00
Sean Leary
7844eb79cd Merge pull request #583 from ek08/fix
Checked the length of key for checker framework
2021-02-01 19:48:06 -06:00
Ehtesham
5b531faa49 Improved the logic for checking the length of key 2021-01-28 15:31:23 +05:30
Ehtesham
31ff8a2291 Checked the length of key for checker framework 2021-01-27 11:35:38 +05:30
Sean Leary
e33f463179 Merge pull request #581 from valfirst/patch-1
Use built-in Gradle shorthand notation for Maven Central repository
2021-01-10 18:35:31 -06:00
Valery Yatsynovich
e77a77e841 Use built-in Gradle shorthand notation for Maven Central repository 2020-12-29 14:16:46 +03:00
Sean Leary
26f48484fd Merge pull request #577 from stranck/master
Added clear() methods to JSONObject and JSONArray
2020-12-07 16:54:18 -06:00
Stranck
efad1d73a7 Added UnitTests
(I hope they works :c)
2020-12-04 04:09:19 +01:00
Stranck
c7130d577a Oops 2020-12-04 01:09:18 +01:00
Stranck
d85eea53bb Update JSONArray.java 2020-12-04 01:07:29 +01:00
Stranck
57ad94ef5e Added clear() methods to JSONObject and JSONArray 2020-12-04 00:49:21 +01:00
Sean Leary
a57eff26d5 Merge pull request #575 from johnjaylward/fix-similar-compare-numbers
Fix similar compare numbers
2020-11-22 15:23:03 -06:00
John J. Aylward
68883b9ff8 update number handling to use new helper method for consistency. 2020-11-19 19:10:08 -05:00
John J. Aylward
11e6b1af7e fixes issue #573 by added specific compare of numeric types 2020-11-19 18:55:49 -05:00
John J. Aylward
e4b76d6588 Add test to demonstrate the issue. See #573 2020-11-19 18:18:27 -05:00
John J. Aylward
3a8193bea4 upgrade junit version 2020-11-19 18:18:02 -05:00
Sean Leary
6bf2692a94 Update README.md 2020-11-15 16:09:50 -06:00
9 changed files with 194 additions and 91 deletions

View File

@@ -3,7 +3,7 @@ JSON in Java [package org.json]
[![Maven Central](https://img.shields.io/maven-central/v/org.json/json.svg)](https://mvnrepository.com/artifact/org.json/json) [![Maven Central](https://img.shields.io/maven-central/v/org.json/json.svg)](https://mvnrepository.com/artifact/org.json/json)
**[Click here if you just want the latest release jar file.](https://repo1.maven.org/maven2/org/json/json/20200518/json-20200518.jar)** **[Click here if you just want the latest release jar file.](https://repo1.maven.org/maven2/org/json/json/20201115/json-20201115.jar)**
# Overview # Overview
@@ -246,6 +246,8 @@ and artifactId "json". For example:
[https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav](https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav) [https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav](https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav)
~~~ ~~~
20210307 Recent commits and potentially breaking fix to JSONPointer
20201115 Recent commits and first release after project structure change 20201115 Recent commits and first release after project structure change
20200518 Recent commits and snapshot before project structure change 20200518 Recent commits and snapshot before project structure change

View File

@@ -13,17 +13,14 @@ apply plugin: 'maven-publish'
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral()
maven { maven {
url = uri('https://oss.sonatype.org/content/repositories/snapshots') url = uri('https://oss.sonatype.org/content/repositories/snapshots')
} }
maven {
url = uri('http://repo.maven.apache.org/maven2')
}
} }
dependencies { dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13.1'
testImplementation 'com.jayway.jsonpath:json-path:2.1.0' testImplementation 'com.jayway.jsonpath:json-path:2.1.0'
testImplementation 'org.mockito:mockito-core:1.9.5' testImplementation 'org.mockito:mockito-core:1.9.5'
} }

View File

@@ -3,7 +3,7 @@
<groupId>org.json</groupId> <groupId>org.json</groupId>
<artifactId>json</artifactId> <artifactId>json</artifactId>
<version>v20200429-SNAPSHOT</version> <version>20210307</version>
<packaging>bundle</packaging> <packaging>bundle</packaging>
<name>JSON in Java</name> <name>JSON in Java</name>
@@ -80,7 +80,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.12</version> <version>4.13.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -567,6 +567,14 @@ public class JSONArray implements Iterable<Object> {
return this.myArrayList.size(); return this.myArrayList.size();
} }
/**
* Removes all of the elements from this JSONArray.
* The JSONArray will be empty after this call returns.
*/
public void clear() {
this.myArrayList.clear();
}
/** /**
* Get the optional object value associated with an index. * Get the optional object value associated with an index.
* *
@@ -1374,6 +1382,8 @@ public class JSONArray implements Iterable<Object> {
if (!((JSONArray)valueThis).similar(valueOther)) { if (!((JSONArray)valueThis).similar(valueOther)) {
return false; return false;
} }
} else if (valueThis instanceof Number && valueOther instanceof Number) {
return JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther);
} else if (!valueThis.equals(valueOther)) { } else if (!valueThis.equals(valueOther)) {
return false; return false;
} }

View File

@@ -973,6 +973,14 @@ public class JSONObject {
return this.map.size(); return this.map.size();
} }
/**
* Removes all of the elements from this JSONObject.
* The JSONObject will be empty after this call returns.
*/
public void clear() {
this.map.clear();
}
/** /**
* Check if JSONObject is empty. * Check if JSONObject is empty.
* *
@@ -1161,8 +1169,7 @@ public class JSONObject {
return new BigDecimal((BigInteger) val); return new BigDecimal((BigInteger) val);
} }
if (val instanceof Double || val instanceof Float){ if (val instanceof Double || val instanceof Float){
final double d = ((Number) val).doubleValue(); if (!numberIsFinite((Number)val)) {
if(Double.isNaN(d)) {
return defaultValue; return defaultValue;
} }
return new BigDecimal(((Number) val).doubleValue()); return new BigDecimal(((Number) val).doubleValue());
@@ -1212,11 +1219,10 @@ public class JSONObject {
return ((BigDecimal) val).toBigInteger(); return ((BigDecimal) val).toBigInteger();
} }
if (val instanceof Double || val instanceof Float){ if (val instanceof Double || val instanceof Float){
final double d = ((Number) val).doubleValue(); if (!numberIsFinite((Number)val)) {
if(Double.isNaN(d)) {
return defaultValue; return defaultValue;
} }
return new BigDecimal(d).toBigInteger(); return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
} }
if (val instanceof Long || val instanceof Integer if (val instanceof Long || val instanceof Integer
|| val instanceof Short || val instanceof Byte){ || val instanceof Short || val instanceof Byte){
@@ -1552,7 +1558,7 @@ public class JSONObject {
// if the first letter in the key is not uppercase, then skip. // if the first letter in the key is not uppercase, then skip.
// This is to maintain backwards compatibility before PR406 // This is to maintain backwards compatibility before PR406
// (https://github.com/stleary/JSON-java/pull/406/) // (https://github.com/stleary/JSON-java/pull/406/)
if (Character.isLowerCase(key.charAt(0))) { if (key.length() == 0 || Character.isLowerCase(key.charAt(0))) {
return null; return null;
} }
if (key.length() == 1) { if (key.length() == 1) {
@@ -2073,6 +2079,8 @@ public class JSONObject {
if (!((JSONArray)valueThis).similar(valueOther)) { if (!((JSONArray)valueThis).similar(valueOther)) {
return false; return false;
} }
} else if (valueThis instanceof Number && valueOther instanceof Number) {
return isNumberSimilar((Number)valueThis, (Number)valueOther);
} else if (!valueThis.equals(valueOther)) { } else if (!valueThis.equals(valueOther)) {
return false; return false;
} }
@@ -2083,6 +2091,55 @@ public class JSONObject {
} }
} }
/**
* Compares two numbers to see if they are similar.
*
* If either of the numbers are Double or Float instances, then they are checked to have
* a finite value. If either value is not finite (NaN or &#177;infinity), then this
* function will always return false. If both numbers are finite, they are first checked
* to be the same type and implement {@link Comparable}. If they do, then the actual
* {@link Comparable#compareTo(Object)} is called. If they are not the same type, or don't
* implement Comparable, then they are converted to {@link BigDecimal}s. Finally the
* BigDecimal values are compared using {@link BigDecimal#compareTo(BigDecimal)}.
*
* @param l the Left value to compare. Can not be <code>null</code>.
* @param r the right value to compare. Can not be <code>null</code>.
* @return true if the numbers are similar, false otherwise.
*/
static boolean isNumberSimilar(Number l, Number r) {
if (!numberIsFinite(l) || !numberIsFinite(r)) {
// non-finite numbers are never similar
return false;
}
// if the classes are the same and implement Comparable
// then use the built in compare first.
if(l.getClass().equals(r.getClass()) && l instanceof Comparable) {
@SuppressWarnings({ "rawtypes", "unchecked" })
int compareTo = ((Comparable)l).compareTo(r);
return compareTo==0;
}
// BigDecimal should be able to handle all of our number types that we support through
// documentation. Convert to BigDecimal first, then use the Compare method to
// decide equality.
final BigDecimal lBigDecimal = objectToBigDecimal(l, null);
final BigDecimal rBigDecimal = objectToBigDecimal(r, null);
if (lBigDecimal == null || rBigDecimal == null) {
return false;
}
return lBigDecimal.compareTo(rBigDecimal) == 0;
}
private static boolean numberIsFinite(Number n) {
if (n instanceof Double && (((Double) n).isInfinite() || ((Double) n).isNaN())) {
return false;
} else if (n instanceof Float && (((Float) n).isInfinite() || ((Float) n).isNaN())) {
return false;
}
return true;
}
/** /**
* Tests if the value should be tried as a decimal. It makes no test if there are actual digits. * Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
* *
@@ -2216,18 +2273,8 @@ public class JSONObject {
* If o is a non-finite number. * If o is a non-finite number.
*/ */
public static void testValidity(Object o) throws JSONException { public static void testValidity(Object o) throws JSONException {
if (o != null) { if (o instanceof Number && !numberIsFinite((Number) o)) {
if (o instanceof Double) { throw new JSONException("JSON does not allow non-finite numbers.");
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.");
}
}
} }
} }
@@ -2354,7 +2401,7 @@ public class JSONObject {
*/ */
public static Object wrap(Object object) { public static Object wrap(Object object) {
try { try {
if (object == null) { if (NULL.equals(object)) {
return NULL; return NULL;
} }
if (object instanceof JSONObject || object instanceof JSONArray if (object instanceof JSONObject || object instanceof JSONArray

View File

@@ -187,10 +187,11 @@ public class JSONPointer {
this.refTokens = new ArrayList<String>(refTokens); this.refTokens = new ArrayList<String>(refTokens);
} }
/**
* @see https://tools.ietf.org/html/rfc6901#section-3
*/
private static String unescape(String token) { private static String unescape(String token) {
return token.replace("~1", "/").replace("~0", "~") return token.replace("~1", "/").replace("~0", "~");
.replace("\\\"", "\"")
.replace("\\\\", "\\");
} }
/** /**
@@ -263,16 +264,15 @@ public class JSONPointer {
/** /**
* Escapes path segment values to an unambiguous form. * Escapes path segment values to an unambiguous form.
* The escape char to be inserted is '~'. The chars to be escaped * The escape char to be inserted is '~'. The chars to be escaped
* are ~, which maps to ~0, and /, which maps to ~1. Backslashes * are ~, which maps to ~0, and /, which maps to ~1.
* and double quote chars are also escaped.
* @param token the JSONPointer segment value to be escaped * @param token the JSONPointer segment value to be escaped
* @return the escaped value for the token * @return the escaped value for the token
*
* @see https://tools.ietf.org/html/rfc6901#section-3
*/ */
private static String escape(String token) { private static String escape(String token) {
return token.replace("~", "~0") return token.replace("~", "~0")
.replace("/", "~1") .replace("/", "~1");
.replace("\\", "\\\\")
.replace("\"", "\\\"");
} }
/** /**

View File

@@ -1254,4 +1254,19 @@ public class JSONArrayTest {
assertEquals("index " + i + " are equal", a1.get(i), a2.get(i)); assertEquals("index " + i + " are equal", a1.get(i), a2.get(i));
} }
} }
/**
* Tests if calling JSONArray clear() method actually makes the JSONArray empty
*/
@Test(expected = JSONException.class)
public void jsonArrayClearMethodTest() {
//Adds random stuff to the JSONArray
JSONArray jsonArray = new JSONArray();
jsonArray.put(123);
jsonArray.put("456");
jsonArray.put(new JSONArray());
jsonArray.clear(); //Clears the JSONArray
assertTrue("expected jsonArray.length() == 0", jsonArray.length() == 0); //Check if its length is 0
jsonArray.getInt(0); //Should throws org.json.JSONException: JSONArray[0] not found
}
} }

View File

@@ -115,10 +115,17 @@ public class JSONObjectTest {
.put("key2", 2) .put("key2", 2)
.put("key3", new String(string1)); .put("key3", new String(string1));
JSONObject obj4 = new JSONObject()
.put("key1", "abc")
.put("key2", 2.0)
.put("key3", new String(string1));
assertFalse("Should eval to false", obj1.similar(obj2)); assertFalse("Should eval to false", obj1.similar(obj2));
assertTrue("Should eval to true", obj1.similar(obj3)); assertTrue("Should eval to true", obj1.similar(obj3));
assertTrue("Should eval to true", obj1.similar(obj4));
} }
@Test @Test
@@ -3208,4 +3215,19 @@ public class JSONObjectTest {
assertNotNull("'empty_json_array' should be an array", jsonObject.getJSONArray("empty_json_array")); assertNotNull("'empty_json_array' should be an array", jsonObject.getJSONArray("empty_json_array"));
assertEquals("'empty_json_array' should have a length of 0", 0, jsonObject.getJSONArray("empty_json_array").length()); assertEquals("'empty_json_array' should have a length of 0", 0, jsonObject.getJSONArray("empty_json_array").length());
} }
/**
* Tests if calling JSONObject clear() method actually makes the JSONObject empty
*/
@Test(expected = JSONException.class)
public void jsonObjectClearMethodTest() {
//Adds random stuff to the JSONObject
JSONObject jsonObject = new JSONObject();
jsonObject.put("key1", 123);
jsonObject.put("key2", "456");
jsonObject.put("key3", new JSONObject());
jsonObject.clear(); //Clears the JSONObject
assertTrue("expected jsonObject.length() == 0", jsonObject.length() == 0); //Check if its length is 0
jsonObject.getInt("key1"); //Should throws org.json.JSONException: JSONObject["asd"] not found
}
} }

View File

@@ -117,14 +117,24 @@ public class JSONPointerTest {
assertSame(document.get("m~n"), query("/m~0n")); assertSame(document.get("m~n"), query("/m~0n"));
} }
/**
* We pass backslashes as-is
*
* @see https://tools.ietf.org/html/rfc6901#section-3
*/
@Test @Test
public void backslashEscaping() { public void backslashHandling() {
assertSame(document.get("i\\j"), query("/i\\\\j")); assertSame(document.get("i\\j"), query("/i\\j"));
} }
/**
* We pass quotations as-is
*
* @see https://tools.ietf.org/html/rfc6901#section-3
*/
@Test @Test
public void quotationEscaping() { public void quotationHandling() {
assertSame(document.get("k\"l"), query("/k\\\\\\\"l")); assertSame(document.get("k\"l"), query("/k\"l"));
} }
@Test @Test
@@ -189,7 +199,7 @@ public class JSONPointerTest {
.append("\"") .append("\"")
.append(0) .append(0)
.build(); .build();
assertEquals("/obj/other~0key/another~1key/\\\"/0", pointer.toString()); assertEquals("/obj/other~0key/another~1key/\"/0", pointer.toString());
} }
@Test @Test