Compare commits

...

45 Commits

Author SHA1 Message Date
Sean Leary
c0e467c848 Merge pull request #613 from stleary/fix-similar-check
Fixes Issue #611 JsonObject.similar() returns after number entry check
2021-07-26 18:12:44 -05:00
stleary
8680b10716 merge from master to pick up #616 and add one more test 2021-07-26 18:07:38 -05:00
stleary
2559114dbb Merge branch 'master' into fix-similar-check 2021-07-26 17:53:20 -05:00
Sean Leary
bb048e3ffb Merge pull request #617 from johnjaylward/issue-616-similar-bug
Fixes #616 similar() problem comparing double vs BigDecimal
2021-07-26 17:47:03 -05:00
John Aylward
579784d73e correct error in converting doubles to big decimals 2021-07-22 23:46:31 -04:00
John Aylward
c03054b1a6 Add test to show bug 2021-07-22 22:57:15 -04:00
John Aylward
4e0faebe62 fix javadoc errors that prevent compilation in Eclipse 2021-07-22 22:54:46 -04:00
stleary
c6089e53f5 Fixes Issue #611 JsonArray.similar() returns after number entry check 2021-07-18 19:53:23 -05:00
stleary
cfbc306673 Fixes Issue #611 JsonObject.similar() returns after number entry check 2021-07-18 10:32:49 -05:00
Sean Leary
449ec8745e Merge pull request #610 from tilds/optJSONObject-defaultValue
New JSONObject.optJSONObject method with defaultValue parameter
2021-06-28 22:01:37 -05:00
Niels Frederiksen
f91d0c8a52 New JSONObject.optJSONObject method with defaultValue parameter 2021-06-23 15:15:00 +02:00
stleary
4571978840 Merge branch 'master' of https://github.com/stleary/JSON-java 2021-06-22 19:46:44 -05:00
stleary
76ec2fe5a2 Revert accidentally changed file 2021-06-22 19:46:33 -05:00
Sean Leary
0200c984cc Update README.md 2021-06-22 19:41:31 -05:00
stleary
8f3e5ade18 Add logo image 2021-06-22 19:34:22 -05:00
Sean Leary
143db39d27 Merge pull request #604 from ianlovejoy/master
Fixed incorrect cast getting float from array
2021-05-01 08:50:54 -05:00
Ian Lovejoy
75894086e5 Fixed incorrect cast getting float from array
Added test for getting float from array
2021-04-27 19:03:35 -07:00
Sean Leary
fa46da45f4 Merge pull request #601 from AISS-2021-L5-G02/master
Added some examples for new-comers in a Markdown file
2021-04-21 00:31:12 -05:00
TheNeoStormZ
f912e5d1c4 Merge pull request #2 from TheNeoStormZ/master
Changed JSONExamples to a Markdown file (and another place) with mino…
2021-04-02 19:31:42 +02:00
Pablo MarĂ­n GĂłmez
6bf3d38889 Changed JSONExamples to a Markdown file (and another place) with minor tweaks 2021-04-02 19:28:37 +02:00
TheNeoStormZ
c62df81b3e Merge pull request #1 from TheNeoStormZ/master
Added some examples for new-comers
2021-04-02 11:28:25 +02:00
Pablo MarĂ­n GĂłmez
e1f69ff3fe Added some examples for new-comers 2021-04-02 11:25:57 +02:00
Sean Leary
50d619698f Merge pull request #594 from anton0xf/patch-1
JSONStringer.java: fix max nesting level in javadoc
2021-03-18 19:42:49 -05:00
anton0xf
29103e3228 JSONStringer.java: fix max nesting level in javadoc 2021-03-14 22:45:38 +05:00
Sean Leary
2630676f36 Update README.md 2021-03-09 19:54:54 -06:00
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
15 changed files with 718 additions and 119 deletions

433
Examples.md Normal file
View File

@@ -0,0 +1,433 @@
<h1>Examples</h1>
<p>Imports used in the examples: </p>
```
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
```
<p>This document's intention is to explain to new-comers the basics of this project</p>
<h2>Part 1: Creating a JSON document</h2>
<h3>Using JSONArray</h3>
```
private static void JSONExampleArray1() {
//We create a JSONObject from a String containing an array using JSONArray
//Firstly, we declare an Array in a String
String arrayStr =
"["+"true,"+"false,"+ "\"true\","+ "\"false\","+"\"hello\","+"23.45e-4,"+
"\"23.45\","+"42,"+"\"43\","+"["+"\"world\""+"],"+
"{"+
"\"key1\":\"value1\","+
"\"key2\":\"value2\","+
"\"key3\":\"value3\","+
"\"key4\":\"value4\""+
"},"+
"0,"+"\"-1\""+
"]";
//Then, we initializate the JSONArray thanks to its constructor
JSONArray array = new JSONArray(arrayStr);
System.out.println("Values array: "+ array);
//We convert that array into a JSONObject, but first, we need the labels, so we need another JSONArray with the labels.
//Here we will use an auxiliary function to get one for the example.
JSONArray list = listNumberArray(array.length());
System.out.println("Label Array: "+ list.toString());
//Now, we construct the JSONObject using both the value array and the label array.
JSONObject object = array.toJSONObject(list);
System.out.println("Final JSONOBject: " + object);
}
//This method creates an JSONArray of labels in which those are generated by their positions
private static JSONArray listNumberArray(int max){
JSONArray res = new JSONArray();
for (int i=0; i<max;i++) {
//The value of the labels must be an String in order to make it work
res.put(String.valueOf(i));
}
return res;
}
```
```
private static void JSONExampleArray2() {
//We can also create an Array without a String by creating an empty array and adding elements to it
JSONArray array = new JSONArray();
//Adding elements with .put()
array.put("value");
array.put(5);
array.put(-23.45e67);
array.put(true);
//We convert it to JSONObject providing a label arrray like last time
JSONArray list = listNumberArray(array.length());
JSONObject object = array.toJSONObject(list);
System.out.println("Final JSONOBject: " + object);
}
```
<h3>Using JSONStringer</h3>
```
private static void JSONExampleStringer() {
//We initializate the JSONStringer
JSONStringer jsonStringer = new JSONStringer();
//Now we start the process of adding elements with .object()
jsonStringer.object();
//We can now add elements as keys and values with .values () and .key()
jsonStringer.key("trueValue").value(true);
jsonStringer.key("falseValue").value(false);
jsonStringer.key("nullValue").value(null);
jsonStringer.key("stringValue").value("hello world!");
jsonStringer.key("complexStringValue").value("h\be\tllo w\u1234orld!");
jsonStringer.key("intValue").value(42);
jsonStringer.key("doubleValue").value(-23.45e67);
//We end this prcedure with .ednObject
jsonStringer.endObject();
//Once we have a JSONStringer, we convert it to JSONObject generating a String and using JSONObject's contructor.
String str = jsonStringer.toString();
JSONObject jsonObject = new JSONObject(str);
System.out.println("Final JSONOBject: " + jsonObject);
}
```
<h3>Using JSONObject</h3>
```
private static void JSONExampleObject1() {
//We can create a JSONObject from a String with the class builder
String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}";
JSONObject example = new JSONObject(string);
System.out.println("Final JSONObject: " + example);
}
```
```
private static void JSONExampleObject2() {
//We can also create a JSONObject directly without messing around with any of the other functions.
JSONObject example = new JSONObject();
//Now we add the keys and values in a similar way as the Stringer method
example.put("key", "value");
//As you can see, the first entry is the key and the second would be its associeted value.
example.put("key2", 5);
example.put("key3", -23.45e67);
example.put("trueValue", true);
//We can't add null values thougth
//example.put("nullValue", null); //This is not possible
System.out.println("Final JSONOBject: " + example);
}
```
```
private static void JSONExampleObject3() {
//We can also create a JSONObject with a Java Map
//YoU will need a Map whose keys are Strings. The values can be whatever you want
Map<String,Double> map = new HashMap<String, Double>();
map.put("key1", 1.0);
map.put("key2", -23.45e67);
//We create the JSONObject with the map with its class builder
JSONObject example = new JSONObject(map);
System.out.println("Final JSONOBject: " + example);
}
```
<h3>Using JSONWriter</h3>
```
private static void JSONExamplWriter() {
//This method works in a very similar way to Object and Stringer in the construction of the JSON.
//The difference is that it needs a Java object called "Appendable" like StringBuilder
StringBuilder write = new StringBuilder();
JSONWriter jsonWriter = new JSONWriter(write);
//We behave now the same way as Stringer
jsonWriter.object();
jsonWriter.key("trueValue").value(true);
jsonWriter.key("falseValue").value(false);
jsonWriter.key("nullValue").value(null);
jsonWriter.key("stringValue").value("hello world!");
jsonWriter.key("complexStringValue").value("h\be\tllo w\u1234orld!");
jsonWriter.key("intValue").value(42);
jsonWriter.key("doubleValue").value(-23.45e67);
jsonWriter.endObject();
//The resoult should be in the "write" object
System.out.println("JSON: " + write.toString());
//The difference is that we don't get a JSONObject in this one.
}
```
```
private static void JSONExampleTokener() {
//A partir de una String podemos crear un JSONTokener, que lo podemos usar alternativamente para JSONArray,JSONObject
String string = "this is not a valid JSON string";
JSONTokener token = new JSONTokener(string);
//Now you can use the token in JSONObject and Array the same way as a String
JSONObject object = new JSONObject(token);
JSONArray array = new JSONArray(token);
}
```
<h2>Part 2: Conversion methods</h2>
<p>We don't need to have a JSON docuemnt to work. This project also admits conversions from other type of files.</p>
<p>Secondly, we can also convert from JSON to those type of files.</p>
<h3>Extra: Conversion to JSONArray</h3>
```
private static void JSONObjectToArray() {
//We start with a JSONObject
String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}";
JSONObject example = new JSONObject(string);
//We need a list of key strings like the reverse operation
JSONArray keyStrings = listNumberArray(example.length());
//Then we convert to the Array using both elelements
JSONArray array = example.toJSONArray(keyStrings);
System.out.println("Final JSONArray: " + array);
}
```
<h3>XML Conversions</h3>
```
private static void XMLToExampleConversion() {
//We start with a JSONObject
String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}";
JSONObject example = new JSONObject(string);
//We obtain a String with XML format with toString()
String output = XML.toString(example);
System.out.println("Final XML: " + output);
}
```
```
private static void XMLFromExampleConversion() {
//We start with a string with the XML format
String string = "<0>value</0><1>5</1><2>-2.345E+68</2><3>true</3>";
//We obtain a JSONObject with toJSONOBject()
JSONObject output = XML.toJSONObject(string);
System.out.println("Final JSONObject: " + output);
}
```
<h3>Cookie Conversions</h3>
```
private static void CookieToExampleConversion() {
//We start with a JSONObject
//The JSONOBject needs to entries that gives the cookie a name and gives the field "name" a name too.
//The Cokkie format doesn't support booleans
String string = "{\"name\":\"Cookie-Name\",\"value\":\"name\",\"1\":5,\"2\":-2.345E68,\"3\":'true'}";
JSONObject example = new JSONObject(string);
//We obtain a String with Cookie format with toString()
String output = Cookie.toString(example);
System.out.println("Final Cookie: " + output);
}
```
```
private static void CookieFromExampleConversion() {
//We start with a string with the Cookie format
String string = "Cookie-Name=name;1=5;2=-2.345E%2b68;3=true";
//We obtain a JSONObject with toJSONOBject()
JSONObject output = Cookie.toJSONObject(string);
System.out.println("Final JSONObject: " + output);
}
```
<h3>HTTP Conversions</h3>
```
private static void HTTPToExampleConversion() {
//We start with a JSONObject
//The JSONObject must have the minimun header for a HTTP request or header
String string = "{\"Method\":\"POST\",\"Request-URI\":'/',\"HTTP-Version\":'HTTP/1.1',\"Value1\":true,\"Value2\":2,\"Value3\":-2.345E68}";
JSONObject example = new JSONObject(string);
//We obtain a String with HTTP format with toString()
String output = HTTP.toString(example);
System.out.println("Final HTTP: " + output);
}
```
```
private static void HTTPFromExampleConversion() {
//We start with a string with the HTTP format
String string = "Final HTTP: POST '/' HTTP/1.1 Value3: -2.345E+68 Value1: true Value2: 2";
//We obtain a JSONObject with toJSONOBject()
JSONObject output = HTTP.toJSONObject(string);
System.out.println("Final JSONObject: " + output);
}
```
<h3>CDL Conversions</h3>
```
private static void CDLToExampleConversion() {
//We start with some JSONObjects with the same values in the keys but different values in the "values"
String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}";
JSONObject example = new JSONObject(string);
String string2 = "{\"0\":\"value2\",\"1\":6,\"2\":-8.345E68,\"3\":false}";
JSONObject example2 = new JSONObject(string2);
//We need now a JSONArray with those JSONObjects
JSONArray array = new JSONArray();
array.put(example);
array.put(example2);
//We obtain a String with XML format with toString()
String output = CDL.toString(array);
System.out.println("Final CDL: \r\n" + output);
}
```
```
private static void CDLFromExampleConversion() {
//We start wtih a String with the CDL format
String string = "0,1,2,3\n"
+ "value,5,-2.345E+68,true\n"
+ "value2,6,-8.345E+68,false";
//We obtain a JSONArray with toJSONOBject()
JSONArray output = CDL.toJSONArray(string);
System.out.println("Final JSONArray: " + output);
}
```
<h3>Properties Conversions</h3>
```
private static Properties PropertyToExampleConversion() {
//We start with a JSONObject
String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}";
JSONObject example = new JSONObject(string);
//We obtain a String with Properties format with toString()
Properties output = Property.toProperties(example);
System.out.println("Final Properties: " + output);
return output;
}
```
```
private static void PropertyFromExampleConversion() {
//We start with a Properties object
Properties input = PropertyToExampleConversion();
//We obtain a JSONObject with toJSONOBject()
JSONObject output = Property.toJSONObject(input);
System.out.println("Final JSONObject: " + output);
}
```
<h2>List of all examples methods</h2>
```
public static void main(String[] args) {
//JSONObjectToArray();
//JSONExampleArray1();
//JSONExampleArray2();
//JSONExampleStringer();
//JSONExampleObject1();
//JSONExampleObject2();
//JSONExampleObject3();
//JSONExamplWriter();
//XMLToExampleConversion();
//XMLFromExampleConversion();
//CookieToExampleConversion();
//CookieFromExampleConversion();
//HTTPToExampleConversion();
//HTTPFromExampleConversion();
//CDLToExampleConversion();
//CDLFromExampleConversion();
//PropertyToExampleConversion();
//PropertyFromExampleConversion();
}
```

View File

@@ -1,9 +1,15 @@
![Json-Java logo](https://github.com/stleary/JSON-java/blob/master/images/JsonJava.png?raw=true)
<sub><sup>image credit: Ismael Pérez Ortiz</sup></sub>
JSON in Java [package org.json] 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://search.maven.org/remotecontent?filepath=org/json/json/20210307/json-20210307.jar)**
# Overview # Overview
@@ -246,6 +252,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'
} }

BIN
images/JsonJava.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

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

@@ -326,7 +326,7 @@ public class JSONArray implements Iterable<Object> {
public float getFloat(int index) throws JSONException { public float getFloat(int index) throws JSONException {
final Object object = this.get(index); final Object object = this.get(index);
if(object instanceof Number) { if(object instanceof Number) {
return ((Float)object).floatValue(); return ((Number)object).floatValue();
} }
try { try {
return Float.parseFloat(object.toString()); return Float.parseFloat(object.toString());
@@ -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,10 @@ 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) {
if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) {
return false;
}
} 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.
* *
@@ -1151,6 +1159,18 @@ public class JSONObject {
* to convert. * to convert.
*/ */
static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) { static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) {
return objectToBigDecimal(val, defaultValue, true);
}
/**
* @param val value to convert
* @param defaultValue default value to return is the conversion doesn't work or is null.
* @param exact When <code>true</code>, then {@link Double} and {@link Float} values will be converted exactly.
* When <code>false</code>, they will be converted to {@link String} values before converting to {@link BigDecimal}.
* @return BigDecimal conversion of the original value, or the defaultValue if unable
* to convert.
*/
static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue, boolean exact) {
if (NULL.equals(val)) { if (NULL.equals(val)) {
return defaultValue; return defaultValue;
} }
@@ -1161,11 +1181,17 @@ 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()); if (exact) {
return new BigDecimal(((Number)val).doubleValue());
}else {
// use the string constructor so that we maintain "nice" values for doubles and floats
// the double constructor will translate doubles to "exact" values instead of the likely
// intended representation
return new BigDecimal(val.toString());
}
} }
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){
@@ -1212,11 +1238,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){
@@ -1364,9 +1389,21 @@ public class JSONObject {
* A key string. * A key string.
* @return A JSONObject which is the value. * @return A JSONObject which is the value.
*/ */
public JSONObject optJSONObject(String key) { public JSONObject optJSONObject(String key) { return this.optJSONObject(key, null); }
/**
* Get an optional JSONObject associated with a key, or the default if there
* is no such key or if the value is not a JSONObject.
*
* @param key
* A key string.
* @param defaultValue
* The default.
* @return An JSONObject which is the value.
*/
public JSONObject optJSONObject(String key, JSONObject defaultValue) {
Object object = this.opt(key); Object object = this.opt(key);
return object instanceof JSONObject ? (JSONObject) object : null; return object instanceof JSONObject ? (JSONObject) object : defaultValue;
} }
/** /**
@@ -1552,7 +1589,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) {
@@ -1621,9 +1658,6 @@ public class JSONObject {
* implementations and interfaces has the annotation. Returns the depth of the * implementations and interfaces has the annotation. Returns the depth of the
* annotation in the hierarchy. * annotation in the hierarchy.
* *
* @param <A>
* type of the annotation
*
* @param m * @param m
* method to check * method to check
* @param annotationClass * @param annotationClass
@@ -2073,6 +2107,10 @@ 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) {
if (!isNumberSimilar((Number)valueThis, (Number)valueOther)) {
return false;
};
} else if (!valueThis.equals(valueOther)) { } else if (!valueThis.equals(valueOther)) {
return false; return false;
} }
@@ -2083,6 +2121,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, false);
final BigDecimal rBigDecimal = objectToBigDecimal(r, null, false);
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 +2303,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 +2431,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 <a href="https://tools.ietf.org/html/rfc6901#section-3">rfc6901 section 3</a>
*/
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 <a href="https://tools.ietf.org/html/rfc6901#section-3">rfc6901 section 3</a>
*/ */
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

@@ -50,7 +50,7 @@ import java.io.StringWriter;
* <p> * <p>
* The first method called must be <code>array</code> or <code>object</code>. * The first method called must be <code>array</code> or <code>object</code>.
* There are no methods for adding commas or colons. JSONStringer adds them for * There are no methods for adding commas or colons. JSONStringer adds them for
* you. Objects and arrays can be nested up to 20 levels deep. * you. Objects and arrays can be nested up to 200 levels deep.
* <p> * <p>
* This can sometimes be easier than using a JSONObject to build a string. * This can sometimes be easier than using a JSONObject to build a string.
* @author JSON.org * @author JSON.org

View File

@@ -94,7 +94,7 @@ public class XMLParserConfiguration {
* Configure the parser string processing to try and convert XML values to JSON values and * Configure the parser string processing to try and convert XML values to JSON values and
* use the passed CDATA Tag Name the processing value. Pass <code>null</code> to * use the passed CDATA Tag Name the processing value. Pass <code>null</code> to
* disable CDATA processing * disable CDATA processing
* @param cDataTagName<code>null</code> to disable CDATA processing. Any other value * @param cDataTagName <code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA. * to use that value as the JSONObject key name to process as CDATA.
* @deprecated This constructor has been deprecated in favor of using the new builder * @deprecated This constructor has been deprecated in favor of using the new builder
* pattern for the configuration. * pattern for the configuration.
@@ -109,7 +109,7 @@ public class XMLParserConfiguration {
* Configure the parser to use custom settings. * Configure the parser to use custom settings.
* @param keepStrings <code>true</code> to parse all values as string. * @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value. * <code>false</code> to try and convert XML string values into a JSON value.
* @param cDataTagName<code>null</code> to disable CDATA processing. Any other value * @param cDataTagName <code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA. * to use that value as the JSONObject key name to process as CDATA.
* @deprecated This constructor has been deprecated in favor of using the new builder * @deprecated This constructor has been deprecated in favor of using the new builder
* pattern for the configuration. * pattern for the configuration.
@@ -182,7 +182,7 @@ public class XMLParserConfiguration {
* When parsing the XML into JSON, specifies if values should be kept as strings (<code>true</code>), or if * When parsing the XML into JSON, specifies if values should be kept as strings (<code>true</code>), 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 {@link #keepStrings} configuration value. * @return The <code>keepStrings</code> configuration value.
*/ */
public boolean isKeepStrings() { public boolean isKeepStrings() {
return this.keepStrings; return this.keepStrings;
@@ -193,7 +193,7 @@ public class XMLParserConfiguration {
* they should try to be guessed into JSON values (numeric, boolean, string) * they should try to be guessed into JSON values (numeric, boolean, string)
* *
* @param newVal * @param newVal
* new value to use for the {@link #keepStrings} configuration option. * new value to use for the <code>keepStrings</code> configuration option.
* *
* @return The existing configuration will not be modified. A new configuration is returned. * @return The existing configuration will not be modified. A new configuration is returned.
*/ */
@@ -208,7 +208,7 @@ public class XMLParserConfiguration {
* been the value "content" but can be changed. Use <code>null</code> to indicate no CDATA * been the value "content" but can be changed. Use <code>null</code> to indicate no CDATA
* processing. * processing.
* *
* @return The {@link #cDataTagName} configuration value. * @return The <code>cDataTagName</code> configuration value.
*/ */
public String getcDataTagName() { public String getcDataTagName() {
return this.cDataTagName; return this.cDataTagName;
@@ -220,7 +220,7 @@ public class XMLParserConfiguration {
* processing. * processing.
* *
* @param newVal * @param newVal
* new value to use for the {@link #cDataTagName} configuration option. * new value to use for the <code>cDataTagName</code> configuration option.
* *
* @return The existing configuration will not be modified. A new configuration is returned. * @return The existing configuration will not be modified. A new configuration is returned.
*/ */
@@ -235,7 +235,7 @@ public class XMLParserConfiguration {
* should be kept as attribute(<code>false</code>), or they should be converted to * should be kept as attribute(<code>false</code>), or they should be converted to
* <code>null</code>(<code>true</code>) * <code>null</code>(<code>true</code>)
* *
* @return The {@link #convertNilAttributeToNull} configuration value. * @return The <code>convertNilAttributeToNull</code> configuration value.
*/ */
public boolean isConvertNilAttributeToNull() { public boolean isConvertNilAttributeToNull() {
return this.convertNilAttributeToNull; return this.convertNilAttributeToNull;
@@ -247,7 +247,7 @@ public class XMLParserConfiguration {
* <code>null</code>(<code>true</code>) * <code>null</code>(<code>true</code>)
* *
* @param newVal * @param newVal
* new value to use for the {@link #convertNilAttributeToNull} configuration option. * new value to use for the <code>convertNilAttributeToNull</code> configuration option.
* *
* @return The existing configuration will not be modified. A new configuration is returned. * @return The existing configuration will not be modified. A new configuration is returned.
*/ */
@@ -262,7 +262,7 @@ public class XMLParserConfiguration {
* will be converted to target type defined to client in this configuration * will be converted to target type defined to client in this configuration
* {@code Map<String, XMLXsiTypeConverter<?>>} to parse values with attribute * {@code Map<String, XMLXsiTypeConverter<?>>} to parse values with attribute
* xsi:type="integer" as integer, xsi:type="string" as string * xsi:type="integer" as integer, xsi:type="string" as string
* @return {@link #xsiTypeMap} unmodifiable configuration map. * @return <code>xsiTypeMap</code> unmodifiable configuration map.
*/ */
public Map<String, XMLXsiTypeConverter<?>> getXsiTypeMap() { public Map<String, XMLXsiTypeConverter<?>> getXsiTypeMap() {
return this.xsiTypeMap; return this.xsiTypeMap;

View File

@@ -87,6 +87,7 @@ public class JSONArrayTest {
@Test @Test
public void verifySimilar() { public void verifySimilar() {
final String string1 = "HasSameRef"; final String string1 = "HasSameRef";
final String string2 = "HasDifferentRef";
JSONArray obj1 = new JSONArray() JSONArray obj1 = new JSONArray()
.put("abc") .put("abc")
.put(string1) .put(string1)
@@ -102,9 +103,19 @@ public class JSONArrayTest {
.put(new String(string1)) .put(new String(string1))
.put(2); .put(2);
assertFalse("Should eval to false", obj1.similar(obj2)); JSONArray obj4 = new JSONArray()
.put("abc")
.put(2.0)
.put(new String(string1));
assertTrue("Should eval to true", obj1.similar(obj3)); JSONArray obj5 = new JSONArray()
.put("abc")
.put(2.0)
.put(new String(string2));
assertFalse("obj1-obj2 Should eval to false", obj1.similar(obj2));
assertTrue("obj1-obj3 Should eval to true", obj1.similar(obj3));
assertFalse("obj4-obj5 Should eval to false", obj4.similar(obj5));
} }
/** /**
@@ -364,6 +375,8 @@ public class JSONArrayTest {
new Double(23.45e-4).equals(jsonArray.getDouble(5))); new Double(23.45e-4).equals(jsonArray.getDouble(5)));
assertTrue("Array string double", assertTrue("Array string double",
new Double(23.45).equals(jsonArray.getDouble(6))); new Double(23.45).equals(jsonArray.getDouble(6)));
assertTrue("Array double can be float",
new Float(23.45e-4f).equals(jsonArray.getFloat(5)));
// ints // ints
assertTrue("Array value int", assertTrue("Array value int",
new Integer(42).equals(jsonArray.getInt(7))); new Integer(42).equals(jsonArray.getInt(7)));
@@ -1254,4 +1267,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

@@ -100,6 +100,7 @@ public class JSONObjectTest {
@Test @Test
public void verifySimilar() { public void verifySimilar() {
final String string1 = "HasSameRef"; final String string1 = "HasSameRef";
final String string2 = "HasDifferentRef";
JSONObject obj1 = new JSONObject() JSONObject obj1 = new JSONObject()
.put("key1", "abc") .put("key1", "abc")
.put("key2", 2) .put("key2", 2)
@@ -115,10 +116,27 @@ 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));
assertTrue("Should eval to true", obj1.similar(obj3)); JSONObject obj5 = new JSONObject()
.put("key1", "abc")
.put("key2", 2.0)
.put("key3", new String(string2));
assertFalse("obj1-obj2 Should eval to false", obj1.similar(obj2));
assertTrue("obj1-obj3 Should eval to true", obj1.similar(obj3));
assertTrue("obj1-obj4 Should eval to true", obj1.similar(obj4));
assertFalse("obj1-obj5 Should eval to false", obj1.similar(obj5));
// verify that a double and big decimal are "similar"
assertTrue("should eval to true",new JSONObject().put("a",1.1d).similar(new JSONObject("{\"a\":1.1}")));
// Confirm #618 is fixed (compare should not exit early if similar numbers are found)
// Note that this test may not work if the JSONObject map entry order changes
JSONObject first = new JSONObject("{\"a\": 1, \"b\": 2, \"c\": 3}");
JSONObject second = new JSONObject("{\"a\": 1, \"b\": 2.0, \"c\": 4}");
assertFalse("first-second should eval to false", first.similar(second));
} }
@Test @Test
@@ -933,7 +951,7 @@ public class JSONObjectTest {
assertTrue("-0 Should be a Double!",JSONObject.stringToValue("-0") instanceof Double); assertTrue("-0 Should be a Double!",JSONObject.stringToValue("-0") instanceof Double);
assertTrue("-0.0 Should be a Double!",JSONObject.stringToValue("-0.0") instanceof Double); assertTrue("-0.0 Should be a Double!",JSONObject.stringToValue("-0.0") instanceof Double);
assertTrue("'-' Should be a String!",JSONObject.stringToValue("-") instanceof String); assertTrue("'-' Should be a String!",JSONObject.stringToValue("-") instanceof String);
assertTrue( "0.2 should be a Double!", assertTrue( "0.2 should be a BigDecimal!",
JSONObject.stringToValue( "0.2" ) instanceof BigDecimal ); JSONObject.stringToValue( "0.2" ) instanceof BigDecimal );
assertTrue( "Doubles should be BigDecimal, even when incorrectly converting floats!", assertTrue( "Doubles should be BigDecimal, even when incorrectly converting floats!",
JSONObject.stringToValue( new Double( "0.2f" ).toString() ) instanceof BigDecimal ); JSONObject.stringToValue( new Double( "0.2f" ).toString() ) instanceof BigDecimal );
@@ -2397,8 +2415,8 @@ public class JSONObjectTest {
MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1)));
assertTrue("optJSONArray() should return null ", assertTrue("optJSONArray() should return null ",
null==jsonObject.optJSONArray("myKey")); null==jsonObject.optJSONArray("myKey"));
assertTrue("optJSONObject() should return null ", assertTrue("optJSONObject() should return default JSONObject ",
null==jsonObject.optJSONObject("myKey")); jsonObject.optJSONObject("myKey", new JSONObject("{\"testKey\":\"testValue\"}")).getString("testKey").equals("testValue"));
assertTrue("optLong() should return default long", assertTrue("optLong() should return default long",
42l == jsonObject.optLong("myKey", 42l)); 42l == jsonObject.optLong("myKey", 42l));
assertTrue("optDouble() should return default double", assertTrue("optDouble() should return default double",
@@ -2433,8 +2451,8 @@ public class JSONObjectTest {
MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1))); MyEnum.VAL1.equals(jsonObject.optEnum(MyEnum.class, "myKey", MyEnum.VAL1)));
assertTrue("optJSONArray() should return null ", assertTrue("optJSONArray() should return null ",
null==jsonObject.optJSONArray("myKey")); null==jsonObject.optJSONArray("myKey"));
assertTrue("optJSONObject() should return null ", assertTrue("optJSONObject() should return default JSONObject ",
null==jsonObject.optJSONObject("myKey")); jsonObject.optJSONObject("myKey", new JSONObject("{\"testKey\":\"testValue\"}")).getString("testKey").equals("testValue"));
assertTrue("optLong() should return default long", assertTrue("optLong() should return default long",
42l == jsonObject.optLong("myKey", 42l)); 42l == jsonObject.optLong("myKey", 42l));
assertTrue("optDouble() should return default double", assertTrue("optDouble() should return default double",
@@ -3208,4 +3226,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 <a href="https://tools.ietf.org/html/rfc6901#section-3">rfc6901 section 3</a>
*/
@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 <a href="https://tools.ietf.org/html/rfc6901#section-3">rfc6901 section 3</a>
*/
@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

View File

@@ -65,6 +65,7 @@ public class XMLTest {
@Rule @Rule
public TemporaryFolder testFolder = new TemporaryFolder(); public TemporaryFolder testFolder = new TemporaryFolder();
/** /**
* JSONObject from a null XML string. * JSONObject from a null XML string.
* Expects a NullPointerException * Expects a NullPointerException

View File

@@ -8,7 +8,7 @@ import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
/** /**
* Object for testing the exception handling in {@link JSONObject#populateMap}. * Object for testing the exception handling in {@link org.json.JSONObject#populateMap}.
* *
* @author John Aylward * @author John Aylward
*/ */