Merge branch 'master' into gh-pages

This commit is contained in:
stleary 2020-12-27 14:53:10 -06:00
commit 7afd93263f
7 changed files with 136 additions and 44 deletions

View File

@ -3,11 +3,11 @@ 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
[JSON](http://www.JSON.org/) is a light-weight language independent data interchange format. [JSON](http://www.JSON.org/) is a light-weight language-independent data interchange format.
The JSON-Java package is a reference implementation that demonstrates how to parse JSON documents into Java objects and how to generate new JSON documents from the Java classes. The JSON-Java package is a reference implementation that demonstrates how to parse JSON documents into Java objects and how to generate new JSON documents from the Java classes.
@ -17,7 +17,7 @@ Project goals include:
* Easy to build, use, and include in other projects * Easy to build, use, and include in other projects
* No external dependencies * No external dependencies
* Fast execution and low memory footprint * Fast execution and low memory footprint
* Maintain backwards compatibility * Maintain backward compatibility
* Designed and tested to use on Java versions 1.6 - 1.11 * Designed and tested to use on Java versions 1.6 - 1.11
The files in this package implement JSON encoders and decoders. The package can also convert between JSON and XML, HTTP headers, Cookies, and CDL. The files in this package implement JSON encoders and decoders. The package can also convert between JSON and XML, HTTP headers, Cookies, and CDL.
@ -26,7 +26,7 @@ The license includes this restriction: ["The software shall be used for good, no
**If you would like to contribute to this project** **If you would like to contribute to this project**
Bug fixes, code improvements, and unit test coverage changes are welcome! Because this project is currrently in maintenance phase, the kinds of changes that can be accepted are limited. For more information, please read the [FAQ](https://github.com/stleary/JSON-java/wiki/FAQ). Bug fixes, code improvements, and unit test coverage changes are welcome! Because this project is currently in the maintenance phase, the kinds of changes that can be accepted are limited. For more information, please read the [FAQ](https://github.com/stleary/JSON-java/wiki/FAQ).
# Build Instructions # Build Instructions
@ -61,7 +61,7 @@ public class Test {
} }
```` ````
*Excecute the Test file* *Execute the Test file*
```` ````
java -cp .;json-java.jar Test java -cp .;json-java.jar Test
```` ````
@ -73,14 +73,14 @@ java -cp .;json-java.jar Test
```` ````
**Build tools for building the package and executing the unit tests** **Tools to build the package and execute the unit tests**
The test suite can be executed with Maven by running: Execute the test suite with Maven:
``` ```
mvn clean test mvn clean test
``` ```
The test suite can be executed with Gradlew by running: Execute the test suite with Gradlew:
``` ```
gradlew clean build test gradlew clean build test
@ -101,12 +101,12 @@ This package fully supports `Integer`, `Long`, and `Double` Java types. Partial
for `BigInteger` and `BigDecimal` values in `JSONObject` and `JSONArray` objects is provided for `BigInteger` and `BigDecimal` values in `JSONObject` and `JSONArray` objects is provided
in the form of `get()`, `opt()`, and `put()` API methods. in the form of `get()`, `opt()`, and `put()` API methods.
Although 1.6 compatibility is currently supported, it is not a project goal and may be Although 1.6 compatibility is currently supported, it is not a project goal and might be
removed in some future release. removed in some future release.
In compliance with RFC8259 page 10 section 9, the parser is more lax with what is valid In compliance with RFC8259 page 10 section 9, the parser is more lax with what is valid
JSON than the Generator. For Example, the tab character (U+0009) is allowed when reading JSON then the Generator. For Example, the tab character (U+0009) is allowed when reading
JSON Text strings, but when output by the Generator, tab is properly converted to \t in JSON Text strings, but when output by the Generator, the tab is properly converted to \t in
the string. Other instances may occur where reading invalid JSON text does not cause an the string. Other instances may occur where reading invalid JSON text does not cause an
error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or
invalid number formats (1.2e6.3) will cause errors as such documents can not be read invalid number formats (1.2e6.3) will cause errors as such documents can not be read
@ -119,7 +119,7 @@ Some notable exceptions that the JSON Parser in this library accepts are:
* Numbers out of range for `Double` or `Long` are parsed as strings * Numbers out of range for `Double` or `Long` are parsed as strings
Recent pull requests added a new method `putAll` on the JSONArray. The `putAll` method Recent pull requests added a new method `putAll` on the JSONArray. The `putAll` method
works similarly as other `put` mehtods in that it does not call `JSONObject.wrap` for items works similarly to other `put` methods in that it does not call `JSONObject.wrap` for items
added. This can lead to inconsistent object representation in JSONArray structures. added. This can lead to inconsistent object representation in JSONArray structures.
For example, code like this will create a mixed JSONArray, some items wrapped, others For example, code like this will create a mixed JSONArray, some items wrapped, others
@ -169,10 +169,10 @@ For example, <b>Cookie.java</b> is tested by <b>CookieTest.java</b>.
<b>General issues with unit testing are:</b><br> <b>General issues with unit testing are:</b><br>
* Just writing tests to make coverage goals tends to result in poor tests. * Just writing tests to make coverage goals tends to result in poor tests.
* Unit tests are a form of documentation - how a given method actually works is demonstrated by the test. So for a code reviewer or future developer looking at code a good test helps explain how a function is supposed to work according to the original author. This can be difficult if you are not the original developer. * Unit tests are a form of documentation - how a given method works is demonstrated by the test. So for a code reviewer or future developer looking at code a good test helps explain how a function is supposed to work according to the original author. This can be difficult if you are not the original developer.
* It is difficult to evaluate unit tests in a vacuum. You also need to see the code being tested to understand if a test is good. * It is difficult to evaluate unit tests in a vacuum. You also need to see the code being tested to understand if a test is good.
* Without unit tests it is hard to feel confident about the quality of the code, especially when fixing bugs or refactoring. Good tests prevents regressions and keeps the intent of the code correct. * Without unit tests, it is hard to feel confident about the quality of the code, especially when fixing bugs or refactoring. Good tests prevent regressions and keep the intent of the code correct.
* If you have unit test results along with pull requests, the reviewer has an easier time understanding your code and determining if the it works as intended. * If you have unit test results along with pull requests, the reviewer has an easier time understanding your code and determining if it works as intended.
# Files # Files
@ -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)
~~~ ~~~
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
20190722 Recent commits 20190722 Recent commits
@ -264,16 +266,12 @@ and artifactId "json". For example:
it is not recommended for use. it is not recommended for use.
Java 1.6 compatability fixed, JSONArray.toList() and JSONObject.toMap(), Java 1.6 compatability fixed, JSONArray.toList() and JSONObject.toMap(),
RFC4180 compatibility, JSONPointer, some exception fixes, optional XML type conversion. RFC4180 compatibility, JSONPointer, some exception fixes, optional XML type conversion.
Contains the latest code as of 7 Aug, 2016 Contains the latest code as of 7 Aug 2016
20160212 Java 1.6 compatibility, OSGi bundle. Contains the latest code as of 12 Feb, 2016. 20160212 Java 1.6 compatibility, OSGi bundle. Contains the latest code as of 12 Feb 2016.
20151123 JSONObject and JSONArray initialization with generics. Contains the 20151123 JSONObject and JSONArray initialization with generics. Contains the latest code as of 23 Nov 2015.
latest code as of 23 Nov, 2015.
20150729 Checkpoint for Maven central repository release. Contains the latest code 20150729 Checkpoint for Maven central repository release. Contains the latest code
as of 29 July, 2015. as of 29 July 2015.
~~~ ~~~

View File

@ -23,7 +23,7 @@ repositories {
} }
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

@ -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){
@ -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

@ -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));
assertFalse("Should eval to false", obj1.similar(obj2)); JSONObject obj4 = new JSONObject()
.put("key1", "abc")
.put("key2", 2.0)
.put("key3", new String(string1));
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
}
} }