86 Commits

Author SHA1 Message Date
Sean Leary
cdf3cf7f81 Update README 2017-10-17 20:05:29 -05:00
Sean Leary
2565abdaaa Merge pull request #362 from johnjaylward/FixXMLUnescape
Fixes XML Unescaping
2017-08-27 10:59:26 -05:00
John J. Aylward
de855c50aa Fixes #361.
* Removes unescape from the XML class calls
* fixes bug with unescape method
* moves unescape logic into the XMLTokener class for more consistency
2017-08-19 18:23:07 -04:00
Sean Leary
4cb1ae802a Merge pull request #360 from migueltt/tokener-fix
Creating a JSONObject from a string that contains a duplicate key (any level) throws a JSONException that includes location
2017-08-17 21:30:01 -05:00
Miguel
2e0a8137bd Removed JSONTokener.back() 2017-08-14 13:01:31 -04:00
Miguel
f177c97258 Replacing tabs with 4-spaces 2017-08-10 19:12:41 -04:00
Miguel
7d8353401a Adding JSONTokener.back() just before throwing JSONException
This forces JSONTokener.syntaxError(..) to point to the last character of the duplicate key.
2017-08-10 19:05:57 -04:00
Miguel
7fed023080 Update to include error location when creating JSONObject from string/text 2017-08-09 21:52:36 -04:00
Sean Leary
d9b8507e6a Merge pull request #354 from johnjaylward/PopulateMapMoreStrict
Updates for populateMap based on discussion in #279 and #264
2017-07-19 18:57:32 -05:00
Sean Leary
d345bc528e Merge pull request #357 from johnjaylward/WriteJavadocUpdate
Update javadoc according to issue #356.
2017-07-15 18:51:18 -05:00
John J. Aylward
6f238a3698 Update javadoc according to issue #356. 2017-07-15 12:17:27 -04:00
John J. Aylward
4dbc5ef803 fixes malformed javadoc 2017-07-09 18:48:40 -04:00
John J. Aylward
5c80c9157d fixes malformed javadoc 2017-07-09 18:47:09 -04:00
John J. Aylward
a129ebe8e4 Adds check for resources opened by our bean mapping 2017-07-09 18:09:14 -04:00
John J. Aylward
641b68dd55 updates javadoc. 2017-07-07 21:33:46 -04:00
John J. Aylward
643b25140f Updates for populateMap based on discussion in #279 and #264 2017-07-07 20:48:42 -04:00
Sean Leary
5024f2d210 Merge pull request #352 from johnjaylward/ErrorMessagePositionFixes
Error message position fixes
2017-07-06 18:07:50 -05:00
John J. Aylward
16baa323cf adds comments 2017-07-03 13:03:02 -04:00
John J. Aylward
52845366bd Fixes more position errors from stepping to new lines and then back. 2017-07-03 13:03:02 -04:00
John J. Aylward
e7e6ed9205 Fixes position reports on errors 2017-06-23 13:40:41 -04:00
Sean Leary
1add1247fa Merge pull request #348 from johnjaylward/ArrayPerformance
Capacity improvements for internal structures
2017-06-12 02:05:26 -05:00
Sean Leary
5b2e5e7579 Merge pull request #347 from ttulka/master
a comment added to explain the use of HashMap
2017-06-11 23:32:06 -05:00
Sean Leary
c9ae1f17d7 Merge pull request #345 from johnjaylward/BetterErrorHandling
Adds JSONException for write value errors
2017-06-11 14:12:48 -05:00
Tomas Tulka
246350bbcd comment added to explain the reason that JSON object is unordered
to avoid implementators' misconceptions and tries to reimplement the
JSON object to keep the elements order
2017-06-09 09:00:17 +02:00
John J. Aylward
2fbe4d96cf change JSONObject(Map) constructor to use the default capacity when a null map is passed 2017-06-08 12:18:04 -04:00
John J. Aylward
3645f91b55 change JSONArray(Collection) constructor to use the default capacity when a null collection is passed 2017-06-08 12:15:03 -04:00
John J. Aylward
9c092753b0 * Updates array constructor and bulk operations to best guess capacity information
* Update JSONObject to allow best guess for initial capacity.
2017-06-08 11:22:23 -04:00
Tomas Tulka
d0f5607998 a comment added to explain the use of HashMap
to avoid misconception of contributors about using HashMap to implement
a JSON object as a unordered collection by the definition
2017-06-08 08:03:14 +02:00
John J. Aylward
ad6bdd715d Adds JSONException for write value errors so serialization errors can be tracked easier 2017-06-05 20:51:57 -04:00
Sean Leary
ef7a5e40be Merge pull request #341 from johnjaylward/OptimizeLoops
Sorry for the late merge, somehow lost track of this pull request.
2017-05-31 20:51:20 -05:00
John J. Aylward
237bf0adb6 more comments 2017-05-31 18:31:02 -04:00
John J. Aylward
f76fbe7005 fixes comments 2017-05-31 18:13:40 -04:00
John J. Aylward
4f5bf16676 * Adds protected entrySet accessor to JSONObject
* Updates loops that request key/value pairs to use the new entrySet accessor
2017-05-23 12:48:44 -04:00
Sean Leary
fbd2be7431 Merge pull request #337 from johnjaylward/OptimizeOpt
Optimizes opt* functions
2017-05-22 22:59:04 -05:00
John J. Aylward
757b6edb03 Merge branch 'master' of github.com:stleary/JSON-java into OptimizeOpt 2017-05-21 13:12:24 -04:00
Sean Leary
f2b642a1ca Merge pull request #336 from johnjaylward/fixSpelling
Numeric enhancements, Refactoring, Fix spelling
2017-05-20 12:37:31 -05:00
John J. Aylward
04d6e83fc2 * Missed JSONArray optFloat and optDouble for the revert
* prevents erasure of stack trace for rethrown exceptions
2017-05-19 09:49:22 -04:00
John J. Aylward
849b392c01 updates the getNumber/optNumber to not return invalid Doubles 2017-05-18 19:49:50 -04:00
John J. Aylward
a7f8ff24df correct string check for JSONObject optBigDecimal and optBigInteger 2017-05-18 14:41:42 -04:00
John J. Aylward
1ab5260a7a * Adds methods getNUmber and getFloat to JSONArray and JSONObject
* Extracts the stringToNumber logic that the optNumber method uses to reuse it between classes
* Fixes -0 issue with optNumber/getNumber
2017-05-18 14:24:34 -04:00
John J. Aylward
c28a2bdf39 * reverts changes to getDouble and related optDouble and optFloat
* Updates optNumber to be smarter about which object it uses to parse strings
2017-05-18 13:07:32 -04:00
John J. Aylward
382f62e781 * Prevent exceptions in cases where the value is not a string.
* Don't call toString when we know it's a string, just cast
2017-05-18 11:41:51 -04:00
John J. Aylward
0c7bd725a6 fixes for javadoc 2017-05-17 11:34:37 -04:00
John J. Aylward
fcdb8671b2 grr, forgot to save changes on last commit 2017-05-17 11:32:44 -04:00
John J. Aylward
c46774cf13 * Update opt* methods for JSONArray
* Add support to JSONArray and JSONObject to optionally get raw number values
* Add support to JSONArray and JSONObject to optionally get float values
2017-05-17 11:29:26 -04:00
John J. Aylward
bd4b180f4e Support for float to BigDecimal in optBigDecimal 2017-05-17 10:51:06 -04:00
John J. Aylward
a8d4e4734f adjustments to opt methods in reference to https://github.com/stleary/JSON-java/issues/334 2017-05-16 19:38:01 -04:00
John J. Aylward
4865f51dd5 change float double literals to be more standard as 1.0f and 1.0d respectively 2017-05-16 15:38:54 -04:00
John J. Aylward
c870094f69 Fixes spelling in comments and removes compile time warnings 2017-05-16 15:35:05 -04:00
Sean Leary
cbd8b18c4a Update README 2017-05-16 00:29:00 -05:00
Sean Leary
f12fa9ba5f Update LICENSE 2017-04-18 08:32:10 -05:00
John J. Aylward
ae1e9e2b6a fix spelling in javadoc comment 2017-04-03 11:59:36 -04:00
Sean Leary
80e2ea2a80 Merge pull request #324 from dtalex/JSONPointerOnBeans
Allow user to invoke query and optQuery ,with a JSONPointer
2017-03-27 20:04:18 -05:00
alessandro rao
2917104b53 Allow user to invoke query and optQuery ,with a JSONPointer,directly
from JSONArray or JSONObject fix JSONArray
2017-02-25 14:35:02 +01:00
alessandro rao
9e0fc5e680 Allow user to invoke query and optQuery ,with a JSONPointer,directly
from JSONArray or JSONObject
2017-02-25 13:27:50 +01:00
Sean Leary
724fb888f7 Merge pull request #317 from johnjaylward/fixLocale
make sure locale independent data is not upper/lowercased incorrectly…
2017-02-19 21:34:17 -06:00
John J. Aylward
eb806f4c14 make sure locale independent data is not upper/lowercased incorrectly. See #315 2017-02-10 10:07:28 -05:00
Sean Leary
5ff8b4cb08 Merge pull request #304 from omarzina/master
[FIX] Update README
2016-12-05 08:58:35 -06:00
joumar
5ef4f58ef1 [FIX] Update README
Fixed C&P typo
2016-12-05 11:55:24 -03:00
Sean Leary
413bb53b48 Merge pull request #288 from johnjaylward/XmlEscape
Bug fixes for XML Encoding and Decoding
2016-11-24 10:01:14 -06:00
Sean Leary
237376eca6 Merge pull request #292 from erosb/master
Provides "#" string evaluation support for JSON Pointer
2016-10-08 10:07:31 -05:00
Bence Erős
e0616a129e fixing #291 2016-10-05 14:57:42 +02:00
John J. Aylward
93ffca36c3 fixes spacing 2016-09-28 20:23:30 -04:00
John J. Aylward
e477d7002b fixes object comparison 2016-09-28 20:22:12 -04:00
John J. Aylward
fb1db9341e Changes encoding to better match the XML spec section 2.2 2016-09-28 20:15:58 -04:00
John J. Aylward
adb0478f66 properly unescape tokens in JSONML for reversability. 2016-09-22 16:23:09 -04:00
John J. Aylward
f58a0f4684 fixes code point appends to string builder 2016-09-22 16:10:49 -04:00
John J. Aylward
c11e09959c Fixes code point output when unescaping code points. XML escapes are an entire code point, not surrogate pairs like in JSON. 2016-09-22 15:40:26 -04:00
John J. Aylward
68f92eb395 Adds more javadoc. 2016-09-22 14:40:39 -04:00
John J. Aylward
34652a8706 Updates to iterate on code points instead of characters and changes the encoding to only encode control characters as defined by ISO standard. 2016-09-22 14:13:14 -04:00
John J. Aylward
a2d3b59394 Implements unicode escaping similar to JSONObject.
* Removes deprecation on XML.stringToValue(). It now provides unescaping for strings to convert XML entities back into values.
* New unescape function to handle XML entities -> value conversion.
2016-09-22 12:38:06 -04:00
Sean Leary
c24be0e4ea Merge pull request #274 from johnjaylward/NumberOutputFix
Fix for number output bug.
2016-09-09 11:42:35 -05:00
John J. Aylward
88f65c5bea Merge branch 'master' of github.com:stleary/JSON-java into NumberOutputFix
# Conflicts:
#	JSONObject.java
2016-08-26 11:32:35 -04:00
Sean Leary
ebe69df8e4 Merge pull request #271 from johnjaylward/EnumCleanup
Update enum support to be more fully featured.
2016-08-19 10:28:04 -05:00
John J. Aylward
2f2cd4dfc5 Fix for number output bug.
java.lang.Number is currently output without any validation. For all java.* Numbers, this is fine, but for custom Number implementations like Complex or Fraction, the resulting JSON output may be invalid.

For example: If a Fraction implementation defines its' toString method as `return numerator + "/" + denominator`, then the resulting JSON output would be something like this:

```json
{ "fraction" : 1/2 }
```

This is not valid JSON.

This commit verifies that the string representation of the number is close to a JSON formatted number by use of the BigDecimal constructor. If the constructor throws a NumberFormatException, then the string value is instead quoted as a string. The example above would instead output like the following:

```json
{ "fraction" : "1/2" }
```
2016-08-17 12:54:30 -04:00
John J. Aylward
349a209df3 Merge remote-tracking branch 'upstream/master' into EnumCleanup 2016-08-15 10:25:27 -04:00
John J. Aylward
7851e9b2e8 revert back changes to Number support 2016-08-15 10:24:38 -04:00
Sean Leary
7232a95c0b Update JSONObject.java
Fixed some typos committed in #249, since reverted, tracking issue is #263
2016-08-15 01:58:54 -05:00
Sean Leary
f96f505188 Update JSONArray.java
Fixed a Javadoc typo, originally fixed in #249, since reverted. This is to address issue #263
2016-08-15 01:53:08 -05:00
John J. Aylward
91107e3e82 Adds support to JSONObject wrap and write methods to explicitly handle Enums.
The new way enums are handled is to always place the actual enum in the
JSONObject/JSONArray. When writing, we always write the actual "name"
of the enum, so even with a toString override on the enum class, the
value remains consistant and compatible with the optEnum/getEnum methods.

The constructor JSONObject(Object) functions the same way as before when
passing an enum and is consistent with other "value" types. For example,
when creating a JSONObject with Long, Boolean, BigDecimal as the constructor
parameter, the value will be treated as a "bean".
2016-08-11 12:22:31 -04:00
Sean Leary
4e8e24d49d Merge pull request #259 from run2000/appendable_v2
JSONWriter uses Appendable (v2)
2016-08-10 21:55:10 -05:00
Sean Leary
f881b61c81 Update XML.java
Removed a problematic JavaDoc in the header comment to a deprecated method
2016-08-10 15:35:26 -05:00
Sean Leary
37582a44ad Update README 2016-08-10 09:13:22 -05:00
Sean Leary
154cfda9aa Merge pull request #261 from stleary/revert-249-master
Revert "reduces the use of unnecessary exceptions"
2016-08-10 09:03:57 -05:00
Sean Leary
45a7decba4 Revert "reduces the use of unnecessary exceptions" 2016-08-09 14:22:06 -05:00
Nicholas Cull
0c157cae75 JSONWriter uses Appendable. 2016-08-08 19:40:10 +10:00
15 changed files with 1345 additions and 494 deletions

View File

@@ -22,7 +22,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
*/
/**
* This provides static methods to convert comma delimited text into a
@@ -70,9 +70,12 @@ public class CDL {
c = x.next();
if (c == q) {
//Handle escaped double-quote
if(x.next() != '\"')
{
x.back();
char nextC = x.next();
if(nextC != '\"') {
// if our quote was the end of the file, don't step
if(nextC > 0) {
x.back();
}
break;
}
}

View File

@@ -1,5 +1,7 @@
package org.json;
import java.util.Map.Entry;
/*
Copyright (c) 2002 JSON.org
@@ -24,8 +26,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import java.util.Iterator;
/**
* Convert a web browser cookie list string to a JSONObject and back.
* @author JSON.org
@@ -39,7 +39,7 @@ public class CookieList {
* The pairs are separated by ';'. The names and the values
* will be unescaped, possibly converting '+' and '%' sequences.
*
* To add a cookie to a cooklist,
* To add a cookie to a cookie list,
* cookielistJSONObject.put(cookieJSONObject.getString("name"),
* cookieJSONObject.getString("value"));
* @param string A cookie list string
@@ -69,18 +69,17 @@ public class CookieList {
*/
public static String toString(JSONObject jo) throws JSONException {
boolean b = false;
Iterator<String> keys = jo.keys();
String string;
StringBuilder sb = new StringBuilder();
while (keys.hasNext()) {
string = keys.next();
if (!jo.isNull(string)) {
for (final Entry<String,?> entry : jo.entrySet()) {
final String key = entry.getKey();
final Object value = entry.getValue();
if (!JSONObject.NULL.equals(value)) {
if (b) {
sb.append(';');
}
sb.append(Cookie.escape(string));
sb.append(Cookie.escape(key));
sb.append("=");
sb.append(Cookie.escape(jo.getString(string)));
sb.append(Cookie.escape(value.toString()));
b = true;
}
}

View File

@@ -24,7 +24,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import java.util.Iterator;
import java.util.Locale;
import java.util.Map.Entry;
/**
* Convert an HTTP header to a JSONObject and back.
@@ -74,7 +75,7 @@ public class HTTP {
String token;
token = x.nextToken();
if (token.toUpperCase().startsWith("HTTP")) {
if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
// Response
@@ -125,8 +126,6 @@ public class HTTP {
* information.
*/
public static String toString(JSONObject jo) throws JSONException {
Iterator<String> keys = jo.keys();
String string;
StringBuilder sb = new StringBuilder();
if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
sb.append(jo.getString("HTTP-Version"));
@@ -146,14 +145,14 @@ public class HTTP {
throw new JSONException("Not enough material for an HTTP header.");
}
sb.append(CRLF);
while (keys.hasNext()) {
string = keys.next();
if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string) &&
!"Reason-Phrase".equals(string) && !"Method".equals(string) &&
!"Request-URI".equals(string) && !jo.isNull(string)) {
sb.append(string);
for (final Entry<String,?> entry : jo.entrySet()) {
final String key = entry.getKey();
if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
!"Reason-Phrase".equals(key) && !"Method".equals(key) &&
!"Request-URI".equals(key) && !JSONObject.NULL.equals(entry.getValue())) {
sb.append(key);
sb.append(": ");
sb.append(jo.getString(string));
sb.append(jo.optString(key));
sb.append(CRLF);
}
}

View File

@@ -78,7 +78,7 @@ import java.util.Map;
* </ul>
*
* @author JSON.org
* @version 2016-07-19
* @version 2016-08/15
*/
public class JSONArray implements Iterable<Object> {
@@ -154,11 +154,13 @@ public class JSONArray implements Iterable<Object> {
* A Collection.
*/
public JSONArray(Collection<?> collection) {
this.myArrayList = new ArrayList<Object>();
if (collection != null) {
for (Object o : collection) {
this.myArrayList.add(JSONObject.wrap(o));
}
if (collection == null) {
this.myArrayList = new ArrayList<Object>();
} else {
this.myArrayList = new ArrayList<Object>(collection.size());
for (Object o: collection){
this.myArrayList.add(JSONObject.wrap(o));
}
}
}
@@ -172,6 +174,7 @@ public class JSONArray implements Iterable<Object> {
this();
if (array.getClass().isArray()) {
int length = Array.getLength(array);
this.myArrayList.ensureCapacity(length);
for (int i = 0; i < length; i += 1) {
this.put(JSONObject.wrap(Array.get(array, i)));
}
@@ -183,7 +186,7 @@ public class JSONArray implements Iterable<Object> {
@Override
public Iterator<Object> iterator() {
return myArrayList.iterator();
return this.myArrayList.iterator();
}
/**
@@ -241,15 +244,54 @@ public class JSONArray implements Iterable<Object> {
public double getDouble(int index) throws JSONException {
Object object = this.get(index);
try {
if (object instanceof Number) {
return ((Number) object).doubleValue();
} else if (object instanceof String) {
return Double.parseDouble((String) object);
}
return object instanceof Number ? ((Number) object).doubleValue()
: Double.parseDouble((String) object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.", e);
}
}
/**
* Get the float value associated with a key.
*
* @param index
* The index must be between 0 and length() - 1.
* @return The numeric value.
* @throws JSONException
* if the key is not found or if the value is not a Number
* object and cannot be converted to a number.
*/
public float getFloat(int index) throws JSONException {
Object object = this.get(index);
try {
return object instanceof Number ? ((Number) object).floatValue()
: Float.parseFloat(object.toString());
} catch (Exception e) {
throw new JSONException("JSONArray[" + index
+ "] is not a number.", e);
}
}
/**
* Get the Number value associated with a key.
*
* @param index
* The index must be between 0 and length() - 1.
* @return The numeric value.
* @throws JSONException
* if the key is not found or if the value is not a Number
* object and cannot be converted to a number.
*/
public Number getNumber(int index) throws JSONException {
Object object = this.get(index);
try {
if (object instanceof Number) {
return (Number)object;
}
return JSONObject.stringToNumber(object.toString());
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.", e);
}
throw new JSONException("JSONArray[" + index + "] is not a number.");
}
/**
@@ -270,9 +312,8 @@ public class JSONArray implements Iterable<Object> {
// JSONException should really take a throwable argument.
// If it did, I would re-implement this with the Enum.valueOf
// method and place any thrown exception in the JSONException
throw new JSONException("JSONObject[" + JSONObject.quote(Integer.toString(index))
+ "] is not an enum of type " + JSONObject.quote(clazz.getSimpleName())
+ ".");
throw new JSONException("JSONArray[" + index + "] is not an enum of type "
+ JSONObject.quote(clazz.getSimpleName()) + ".");
}
return val;
}
@@ -293,7 +334,7 @@ public class JSONArray implements Iterable<Object> {
return new BigDecimal(object.toString());
} catch (Exception e) {
throw new JSONException("JSONArray[" + index +
"] could not convert to BigDecimal.");
"] could not convert to BigDecimal.", e);
}
}
@@ -313,7 +354,7 @@ public class JSONArray implements Iterable<Object> {
return new BigInteger(object.toString());
} catch (Exception e) {
throw new JSONException("JSONArray[" + index +
"] could not convert to BigInteger.");
"] could not convert to BigInteger.", e);
}
}
@@ -329,15 +370,11 @@ public class JSONArray implements Iterable<Object> {
public int getInt(int index) throws JSONException {
Object object = this.get(index);
try {
if (object instanceof Number) {
return ((Number) object).intValue();
} else if (object instanceof String) {
return Integer.parseInt((String) object);
}
return object instanceof Number ? ((Number) object).intValue()
: Integer.parseInt((String) object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.", e);
}
throw new JSONException("JSONArray[" + index + "] is not a number.");
}
/**
@@ -389,15 +426,11 @@ public class JSONArray implements Iterable<Object> {
public long getLong(int index) throws JSONException {
Object object = this.get(index);
try {
if (object instanceof Number) {
return ((Number) object).longValue();
} else if (object instanceof String) {
return Long.parseLong((String) object);
}
return object instanceof Number ? ((Number) object).longValue()
: Long.parseLong((String) object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.", e);
}
throw new JSONException("JSONArray[" + index + "] is not a number.");
}
/**
@@ -465,7 +498,7 @@ public class JSONArray implements Iterable<Object> {
* Get the optional object value associated with an index.
*
* @param index
* The index must be between 0 and length() - 1.
* The index must be between 0 and length() - 1. If not, null is returned.
* @return An object value, or null if there is no object at that index.
*/
public Object opt(int index) {
@@ -498,20 +531,11 @@ public class JSONArray implements Iterable<Object> {
* @return The truth.
*/
public boolean optBoolean(int index, boolean defaultValue) {
Object object = this.opt(index);
if (JSONObject.NULL.equals(object)) {
try {
return this.getBoolean(index);
} catch (Exception e) {
return defaultValue;
}
if (object.equals(Boolean.FALSE)
|| (object instanceof String && ((String) object)
.equalsIgnoreCase("false"))) {
return false;
} else if (object.equals(Boolean.TRUE)
|| (object instanceof String && ((String) object)
.equalsIgnoreCase("true"))) {
return true;
}
return defaultValue;
}
/**
@@ -539,18 +563,61 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public double optDouble(int index, double defaultValue) {
Object object = this.opt(index);
if (JSONObject.NULL.equals(object)) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
try {
if (object instanceof Number) {
return ((Number) object).doubleValue();
} else if (object instanceof String) {
return Double.parseDouble((String) object);
if (val instanceof Number){
return ((Number) val).doubleValue();
}
if (val instanceof String) {
try {
return Double.parseDouble((String) val);
} catch (Exception e) {
return defaultValue;
}
} catch (Exception e) {
}
return defaultValue;
}
/**
* Get the optional float value associated with an index. NaN is returned
* if there is no value for the index, or if the value is not a number and
* cannot be converted to a number.
*
* @param index
* The index must be between 0 and length() - 1.
* @return The value.
*/
public float optFloat(int index) {
return this.optFloat(index, Float.NaN);
}
/**
* Get the optional float value associated with an index. The defaultValue
* is returned if there is no value for the index, or if the value is not a
* number and cannot be converted to a number.
*
* @param index
* subscript
* @param defaultValue
* The default value.
* @return The value.
*/
public float optFloat(int index, float defaultValue) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof Number){
return ((Number) val).floatValue();
}
if (val instanceof String) {
try {
return Float.parseFloat((String) val);
} catch (Exception e) {
return defaultValue;
}
}
return defaultValue;
}
@@ -580,18 +647,20 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public int optInt(int index, int defaultValue) {
Object object = this.opt(index);
if (JSONObject.NULL.equals(object)) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
try {
if (object instanceof Number) {
return ((Number) object).intValue();
} else if (object instanceof String) {
return Integer.parseInt((String) object);
if (val instanceof Number){
return ((Number) val).intValue();
}
if (val instanceof String) {
try {
return new BigDecimal(val.toString()).intValue();
} catch (Exception e) {
return defaultValue;
}
} catch (Exception e) {
}
return defaultValue;
}
@@ -654,12 +723,29 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public BigInteger optBigInteger(int index, BigInteger defaultValue) {
Object object = this.opt(index);
if (JSONObject.NULL.equals(object)) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof BigInteger){
return (BigInteger) val;
}
if (val instanceof BigDecimal){
return ((BigDecimal) val).toBigInteger();
}
if (val instanceof Double || val instanceof Float){
return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
}
if (val instanceof Long || val instanceof Integer
|| val instanceof Short || val instanceof Byte){
return BigInteger.valueOf(((Number) val).longValue());
}
try {
return new BigInteger(object.toString());
final String valStr = val.toString();
if(JSONObject.isDecimalNotation(valStr)) {
return new BigDecimal(valStr).toBigInteger();
}
return new BigInteger(valStr);
} catch (Exception e) {
return defaultValue;
}
@@ -677,12 +763,25 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) {
Object object = this.opt(index);
if (JSONObject.NULL.equals(object)) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof BigDecimal){
return (BigDecimal) val;
}
if (val instanceof BigInteger){
return new BigDecimal((BigInteger) val);
}
if (val instanceof Double || val instanceof Float){
return new BigDecimal(((Number) val).doubleValue());
}
if (val instanceof Long || val instanceof Integer
|| val instanceof Short || val instanceof Byte){
return new BigDecimal(((Number) val).longValue());
}
try {
return new BigDecimal(object.toString());
return new BigDecimal(val.toString());
} catch (Exception e) {
return defaultValue;
}
@@ -740,18 +839,65 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public long optLong(int index, long defaultValue) {
Object object = this.opt(index);
if (JSONObject.NULL.equals(object)) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
try {
if (object instanceof Number) {
return ((Number) object).longValue();
} else if (object instanceof String) {
return Long.parseLong((String) object);
if (val instanceof Number){
return ((Number) val).longValue();
}
if (val instanceof String) {
try {
return new BigDecimal(val.toString()).longValue();
} catch (Exception e) {
return defaultValue;
}
} catch (Exception e) {
}
return defaultValue;
}
/**
* Get an optional {@link Number} value associated with a key, or <code>null</code>
* if there is no such key or if the value is not a number. If the value is a string,
* an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method
* would be used in cases where type coercion of the number value is unwanted.
*
* @param index
* The index must be between 0 and length() - 1.
* @return An object which is the value.
*/
public Number optNumber(int index) {
return this.optNumber(index, null);
}
/**
* Get an optional {@link Number} value associated with a key, or the default if there
* is no such key or if the value is not a number. If the value is a string,
* an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method
* would be used in cases where type coercion of the number value is unwanted.
*
* @param index
* The index must be between 0 and length() - 1.
* @param defaultValue
* The default.
* @return An object which is the value.
*/
public Number optNumber(int index, Number defaultValue) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof Number){
return (Number) val;
}
if (val instanceof String) {
try {
return JSONObject.stringToNumber((String) val);
} catch (Exception e) {
return defaultValue;
}
}
return defaultValue;
}
@@ -759,7 +905,7 @@ public class JSONArray implements Iterable<Object> {
/**
* Get the optional string value associated with an index. It returns an
* empty string if there is no value at that index. If the value is not a
* string and is not null, then it is coverted to a string.
* string and is not null, then it is converted to a string.
*
* @param index
* The index must be between 0 and length() - 1.
@@ -1007,7 +1153,13 @@ public class JSONArray implements Iterable<Object> {
}
if (index < this.length()) {
this.myArrayList.set(index, value);
} else if(index == this.length()){
// simple append
this.put(value);
} else {
// if we are inserting past the length, we want to grow the array all at once
// instead of incrementally.
this.myArrayList.ensureCapacity(index + 1);
while (index != this.length()) {
this.put(JSONObject.NULL);
}
@@ -1017,7 +1169,7 @@ public class JSONArray implements Iterable<Object> {
}
/**
* Creates a JSONPointer using an initialization string and tries to
* Creates a JSONPointer using an initialization string and tries to
* match it to an item within this JSONArray. For example, given a
* JSONArray initialized with this document:
* <pre>
@@ -1036,7 +1188,30 @@ public class JSONArray implements Iterable<Object> {
* @return the item matched by the JSONPointer, otherwise null
*/
public Object query(String jsonPointer) {
return new JSONPointer(jsonPointer).queryFrom(this);
return query(new JSONPointer(jsonPointer));
}
/**
* Uses a uaer initialized JSONPointer and tries to
* match it to an item whithin this JSONArray. For example, given a
* JSONArray initialized with this document:
* <pre>
* [
* {"b":"c"}
* ]
* </pre>
* and this JSONPointer:
* <pre>
* "/0/b"
* </pre>
* Then this method will return the String "c"
* A JSONPointerException may be thrown from code called by this method.
*
* @param jsonPointer string that can be used to create a JSONPointer
* @return the item matched by the JSONPointer, otherwise null
*/
public Object query(JSONPointer jsonPointer) {
return jsonPointer.queryFrom(this);
}
/**
@@ -1048,9 +1223,20 @@ public class JSONArray implements Iterable<Object> {
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
public Object optQuery(String jsonPointer) {
JSONPointer pointer = new JSONPointer(jsonPointer);
return optQuery(new JSONPointer(jsonPointer));
}
/**
* Queries and returns a value from this object using {@code jsonPointer}, or
* returns null if the query fails due to a missing key.
*
* @param jsonPointer The JSON pointer
* @return the queried value or {@code null}
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
public Object optQuery(JSONPointer jsonPointer) {
try {
return pointer.queryFrom(this);
return jsonPointer.queryFrom(this);
} catch (JSONPointerException e) {
return null;
}
@@ -1086,8 +1272,14 @@ public class JSONArray implements Iterable<Object> {
return false;
}
for (int i = 0; i < len; i += 1) {
Object valueThis = this.get(i);
Object valueOther = ((JSONArray)other).get(i);
Object valueThis = this.myArrayList.get(i);
Object valueOther = ((JSONArray)other).myArrayList.get(i);
if(valueThis == valueOther) {
return true;
}
if(valueThis == null) {
return false;
}
if (valueThis instanceof JSONObject) {
if (!((JSONObject)valueThis).similar(valueOther)) {
return false;
@@ -1119,7 +1311,7 @@ public class JSONArray implements Iterable<Object> {
if (names == null || names.length() == 0 || this.length() == 0) {
return null;
}
JSONObject jo = new JSONObject();
JSONObject jo = new JSONObject(names.length());
for (int i = 0; i < names.length(); i += 1) {
jo.put(names.getString(i), this.opt(i));
}
@@ -1131,8 +1323,9 @@ public class JSONArray implements Iterable<Object> {
* whitespace is added. If it is not possible to produce a syntactically
* correct JSON text then null will be returned instead. This could occur if
* the array contains an invalid number.
* <p>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @return a printable, displayable, transmittable representation of the
* array.
@@ -1147,9 +1340,24 @@ public class JSONArray implements Iterable<Object> {
}
/**
* Make a prettyprinted JSON text of this JSONArray. Warning: This method
* assumes that the data structure is acyclical.
*
* Make a pretty-printed JSON text of this JSONArray.
*
* <p>If <code>indentFactor > 0</code> and the {@link JSONArray} has only
* one element, then the array will be output on a single line:
* <pre>{@code [1]}</pre>
*
* <p>If an array has 2 or more elements, then it will be output across
* multiple lines: <pre>{@code
* [
* 1,
* "value 2",
* 3
* ]
* }</pre>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param indentFactor
* The number of spaces to add to each level of indentation.
* @return a printable, displayable, transmittable representation of the
@@ -1168,8 +1376,9 @@ public class JSONArray implements Iterable<Object> {
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
*</b>
*
* @return The writer.
* @throws JSONException
@@ -1179,17 +1388,30 @@ public class JSONArray implements Iterable<Object> {
}
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* Write the contents of the JSONArray as JSON text to a writer.
*
* <p>If <code>indentFactor > 0</code> and the {@link JSONArray} has only
* one element, then the array will be output on a single line:
* <pre>{@code [1]}</pre>
*
* <p>If an array has 2 or more elements, then it will be output across
* multiple lines: <pre>{@code
* [
* 1,
* "value 2",
* 3
* ]
* }</pre>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param writer
* Writes the serialized JSON
* @param indentFactor
* The number of spaces to add to each level of indentation.
* @param indent
* The indention of the top level.
* The indentation of the top level.
* @return The writer.
* @throws JSONException
*/
@@ -1201,8 +1423,12 @@ public class JSONArray implements Iterable<Object> {
writer.write('[');
if (length == 1) {
JSONObject.writeValue(writer, this.myArrayList.get(0),
indentFactor, indent);
try {
JSONObject.writeValue(writer, this.myArrayList.get(0),
indentFactor, indent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: 0", e);
}
} else if (length != 0) {
final int newindent = indent + indentFactor;
@@ -1214,8 +1440,12 @@ public class JSONArray implements Iterable<Object> {
writer.write('\n');
}
JSONObject.indent(writer, newindent);
JSONObject.writeValue(writer, this.myArrayList.get(i),
indentFactor, newindent);
try {
JSONObject.writeValue(writer, this.myArrayList.get(i),
indentFactor, newindent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: " + i, e);
}
commanate = true;
}
if (indentFactor > 0) {

View File

@@ -1,5 +1,7 @@
package org.json;
import java.util.Map.Entry;
/*
Copyright (c) 2008 JSON.org
@@ -24,9 +26,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import java.util.Iterator;
/**
* This provides static methods to convert an XML text into a JSONArray or
* JSONObject, and to covert a JSONArray or JSONObject into an XML text using
@@ -42,7 +41,7 @@ public class JSONML {
* @param arrayForm true if array form, false if object form.
* @param ja The JSONArray that is containing the current tag or null
* if we are at the outermost level.
* @param keepStrings Don't type-convert text nodes and attibute values
* @param keepStrings Don't type-convert text nodes and attribute values
* @return A JSONArray if the value is the outermost tag, otherwise null.
* @throws JSONException
*/
@@ -175,7 +174,7 @@ public class JSONML {
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
newjo.accumulate(attribute, keepStrings ? token :JSONObject.stringToValue((String)token));
newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token));
token = null;
} else {
newjo.accumulate(attribute, "");
@@ -226,7 +225,7 @@ public class JSONML {
} else {
if (ja != null) {
ja.put(token instanceof String
? keepStrings ? token :JSONObject.stringToValue((String)token)
? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)
: token);
}
}
@@ -397,13 +396,10 @@ public class JSONML {
public static String toString(JSONArray ja) throws JSONException {
int i;
JSONObject jo;
String key;
Iterator<String> keys;
int length;
Object object;
StringBuilder sb = new StringBuilder();
String tagName;
String value;
// Emit <tagName
@@ -420,17 +416,16 @@ public class JSONML {
// Emit the attributes
keys = jo.keys();
while (keys.hasNext()) {
key = keys.next();
for (final Entry<String, ?> entry : jo.entrySet()) {
final String key = entry.getKey();
XML.noSpace(key);
value = jo.optString(key);
final Object value = entry.getValue();
if (value != null) {
sb.append(' ');
sb.append(XML.escape(key));
sb.append('=');
sb.append('"');
sb.append(XML.escape(value));
sb.append(XML.escape(value.toString()));
sb.append('"');
}
}
@@ -482,12 +477,10 @@ public class JSONML {
StringBuilder sb = new StringBuilder();
int i;
JSONArray ja;
String key;
Iterator<String> keys;
int length;
Object object;
String tagName;
String value;
Object value;
//Emit <tagName
@@ -502,18 +495,17 @@ public class JSONML {
//Emit the attributes
keys = jo.keys();
while (keys.hasNext()) {
key = keys.next();
for (final Entry<String, ?> entry : jo.entrySet()) {
final String key = entry.getKey();
if (!"tagName".equals(key) && !"childNodes".equals(key)) {
XML.noSpace(key);
value = jo.optString(key);
value = entry.getValue();
if (value != null) {
sb.append(' ');
sb.append(XML.escape(key));
sb.append('=');
sb.append('"');
sb.append(XML.escape(value));
sb.append(XML.escape(value.toString()));
sb.append('"');
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -68,11 +68,11 @@ public class JSONPointer {
* {@link #append(String)} method calls.
*/
public JSONPointer build() {
return new JSONPointer(refTokens);
return new JSONPointer(this.refTokens);
}
/**
* Adds an arbitary token to the list of reference tokens. It can be any non-null value.
* Adds an arbitrary token to the list of reference tokens. It can be any non-null value.
*
* Unlike in the case of JSON string or URI fragment representation of JSON pointers, the
* argument of this method MUST NOT be escaped. If you want to query the property called
@@ -87,7 +87,7 @@ public class JSONPointer {
if (token == null) {
throw new NullPointerException("token cannot be null");
}
refTokens.add(token);
this.refTokens.add(token);
return this;
}
@@ -99,7 +99,7 @@ public class JSONPointer {
* @return {@code this}
*/
public Builder append(int arrayIndex) {
refTokens.add(String.valueOf(arrayIndex));
this.refTokens.add(String.valueOf(arrayIndex));
return this;
}
}
@@ -134,29 +134,30 @@ public class JSONPointer {
* @param pointer the JSON String or URI Fragment representation of the JSON pointer.
* @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer
*/
public JSONPointer(String pointer) {
public JSONPointer(final String pointer) {
if (pointer == null) {
throw new NullPointerException("pointer cannot be null");
}
if (pointer.isEmpty()) {
refTokens = Collections.emptyList();
if (pointer.isEmpty() || pointer.equals("#")) {
this.refTokens = Collections.emptyList();
return;
}
String refs;
if (pointer.startsWith("#/")) {
pointer = pointer.substring(2);
refs = pointer.substring(2);
try {
pointer = URLDecoder.decode(pointer, ENCODING);
refs = URLDecoder.decode(refs, ENCODING);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
} else if (pointer.startsWith("/")) {
pointer = pointer.substring(1);
refs = pointer.substring(1);
} else {
throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'");
}
refTokens = new ArrayList<String>();
for (String token : pointer.split("/")) {
refTokens.add(unescape(token));
this.refTokens = new ArrayList<String>();
for (String token : refs.split("/")) {
this.refTokens.add(unescape(token));
}
}
@@ -181,11 +182,11 @@ public class JSONPointer {
* @throws JSONPointerException if an error occurs during evaluation
*/
public Object queryFrom(Object document) {
if (refTokens.isEmpty()) {
if (this.refTokens.isEmpty()) {
return document;
}
Object current = document;
for (String token : refTokens) {
for (String token : this.refTokens) {
if (current instanceof JSONObject) {
current = ((JSONObject) current).opt(unescape(token));
} else if (current instanceof JSONArray) {
@@ -206,6 +207,7 @@ public class JSONPointer {
* @return the matched object. If no matching item is found a
* JSONPointerException is thrown
*/
@SuppressWarnings("boxing")
private Object readByIndexToken(Object current, String indexToken) {
try {
int index = Integer.parseInt(indexToken);
@@ -227,7 +229,7 @@ public class JSONPointer {
@Override
public String toString() {
StringBuilder rval = new StringBuilder("");
for (String token: refTokens) {
for (String token: this.refTokens) {
rval.append('/').append(escape(token));
}
return rval.toString();
@@ -255,7 +257,7 @@ public class JSONPointer {
public String toURIFragment() {
try {
StringBuilder rval = new StringBuilder("#");
for (String token : refTokens) {
for (String token : this.refTokens) {
rval.append('/').append(URLEncoder.encode(token, ENCODING));
}
return rval.toString();

View File

@@ -72,6 +72,7 @@ public class JSONStringer extends JSONWriter {
* <code>endArray</code>).
* @return The JSON text.
*/
@Override
public String toString() {
return this.mode == 'd' ? this.writer.toString() : null;
}

View File

@@ -29,7 +29,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
*/
/**
* A JSONTokener takes a source string and extracts characters and tokens from
@@ -39,36 +39,45 @@ SOFTWARE.
* @version 2014-05-03
*/
public class JSONTokener {
private long character;
/** current read character position on the current line. */
private long character;
/** flag to indicate if the end of the input has been found. */
private boolean eof;
private long index;
private long line;
private char previous;
private Reader reader;
/** current read index of the input. */
private long index;
/** current line of the input. */
private long line;
/** previous character read from the input. */
private char previous;
/** Reader for the input. */
private final Reader reader;
/** flag to indicate that a previous character was requested. */
private boolean usePrevious;
/** the number of characters read in the previous line. */
private long characterPreviousLine;
/**
* Construct a JSONTokener from a Reader.
* Construct a JSONTokener from a Reader. The caller must close the Reader.
*
* @param reader A reader.
*/
public JSONTokener(Reader reader) {
this.reader = reader.markSupported()
? reader
: new BufferedReader(reader);
? reader
: new BufferedReader(reader);
this.eof = false;
this.usePrevious = false;
this.previous = 0;
this.index = 0;
this.character = 1;
this.characterPreviousLine = 0;
this.line = 1;
}
/**
* Construct a JSONTokener from an InputStream.
* Construct a JSONTokener from an InputStream. The caller must close the input stream.
* @param inputStream The source.
*/
public JSONTokener(InputStream inputStream) {
@@ -97,12 +106,23 @@ public class JSONTokener {
if (this.usePrevious || this.index <= 0) {
throw new JSONException("Stepping back two steps is not supported");
}
this.index -= 1;
this.character -= 1;
this.decrementIndexes();
this.usePrevious = true;
this.eof = false;
}
/**
* Decrements the indexes for the {@link #back()} method based on the previous character read.
*/
private void decrementIndexes() {
this.index--;
if(this.previous=='\r' || this.previous == '\n') {
this.line--;
this.character=this.characterPreviousLine ;
} else if(this.character > 0){
this.character--;
}
}
/**
* Get the hex value of a character (base16).
@@ -124,6 +144,8 @@ public class JSONTokener {
}
/**
* Checks if the end of the input has been reached.
*
* @return true if at the end of the file and we didn't step back
*/
public boolean end() {
@@ -139,11 +161,24 @@ public class JSONTokener {
* or backward while checking for more data.
*/
public boolean more() throws JSONException {
this.next();
if (this.end()) {
return false;
if(this.usePrevious) {
return true;
}
try {
this.reader.mark(1);
} catch (IOException e) {
throw new JSONException("Unable to preserve stream position", e);
}
try {
// -1 is EOF, but next() can not consume the null character '\0'
if(this.reader.read() <= 0) {
this.eof = true;
return false;
}
this.reader.reset();
} catch (IOException e) {
throw new JSONException("Unable to read the next character from the stream", e);
}
this.back();
return true;
}
@@ -165,26 +200,39 @@ public class JSONTokener {
} catch (IOException exception) {
throw new JSONException(exception);
}
if (c <= 0) { // End of stream
this.eof = true;
c = 0;
}
}
this.index += 1;
if (this.previous == '\r') {
this.line += 1;
this.character = c == '\n' ? 0 : 1;
} else if (c == '\n') {
this.line += 1;
this.character = 0;
} else {
this.character += 1;
if (c <= 0) { // End of stream
this.eof = true;
return 0;
}
this.incrementIndexes(c);
this.previous = (char) c;
return this.previous;
}
/**
* Increments the internal indexes according to the previous character
* read and the character passed as the current character.
* @param c the current character read.
*/
private void incrementIndexes(int c) {
if(c > 0) {
this.index++;
if(c=='\r') {
this.line++;
this.characterPreviousLine = this.character;
this.character=0;
}else if (c=='\n') {
if(this.previous != '\r') {
this.line++;
this.characterPreviousLine = this.character;
}
this.character=0;
} else {
this.character++;
}
}
}
/**
* Consume the next character, and check that it matches a specified
@@ -196,8 +244,11 @@ public class JSONTokener {
public char next(char c) throws JSONException {
char n = this.next();
if (n != c) {
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
n + "'");
if(n > 0) {
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
n + "'");
}
throw this.syntaxError("Expected '" + c + "' and instead saw ''");
}
return n;
}
@@ -212,23 +263,23 @@ public class JSONTokener {
* Substring bounds error if there are not
* n characters remaining in the source string.
*/
public String next(int n) throws JSONException {
if (n == 0) {
return "";
}
public String next(int n) throws JSONException {
if (n == 0) {
return "";
}
char[] chars = new char[n];
int pos = 0;
char[] chars = new char[n];
int pos = 0;
while (pos < n) {
chars[pos] = this.next();
if (this.end()) {
throw this.syntaxError("Substring bounds error");
}
pos += 1;
}
return new String(chars);
}
while (pos < n) {
chars[pos] = this.next();
if (this.end()) {
throw this.syntaxError("Substring bounds error");
}
pos += 1;
}
return new String(chars);
}
/**
@@ -372,15 +423,15 @@ public class JSONTokener {
String string;
switch (c) {
case '"':
case '\'':
return this.nextString(c);
case '{':
this.back();
return new JSONObject(this);
case '[':
this.back();
return new JSONArray(this);
case '"':
case '\'':
return this.nextString(c);
case '{':
this.back();
return new JSONObject(this);
case '[':
this.back();
return new JSONArray(this);
}
/*
@@ -426,13 +477,17 @@ public class JSONTokener {
do {
c = this.next();
if (c == 0) {
// in some readers, reset() may throw an exception if
// the remaining portion of the input is greater than
// the mark size (1,000,000 above).
this.reader.reset();
this.index = startIndex;
this.character = startCharacter;
this.line = startLine;
return c;
return 0;
}
} while (c != to);
this.reader.mark(1);
} catch (IOException exception) {
throw new JSONException(exception);
}
@@ -440,7 +495,6 @@ public class JSONTokener {
return c;
}
/**
* Make a JSONException to signal a syntax error.
*
@@ -470,6 +524,6 @@ public class JSONTokener {
@Override
public String toString() {
return " at " + this.index + " [character " + this.character + " line " +
this.line + "]";
this.line + "]";
}
}

View File

@@ -1,7 +1,6 @@
package org.json;
import java.io.IOException;
import java.io.Writer;
/*
Copyright (c) 2006 JSON.org
@@ -50,11 +49,11 @@ SOFTWARE.
* <p>
* The first method called must be <code>array</code> or <code>object</code>.
* There are no methods for adding commas or colons. JSONWriter 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>
* This can sometimes be easier than using a JSONObject to build a string.
* @author JSON.org
* @version 2015-12-09
* @version 2016-08-08
*/
public class JSONWriter {
private static final int maxdepth = 200;
@@ -88,12 +87,12 @@ public class JSONWriter {
/**
* The writer that will receive the output.
*/
protected Writer writer;
protected Appendable writer;
/**
* Make a fresh JSONWriter. It can be used to build one JSON text.
*/
public JSONWriter(Writer w) {
public JSONWriter(Appendable w) {
this.comma = false;
this.mode = 'i';
this.stack = new JSONObject[maxdepth];
@@ -114,9 +113,9 @@ public class JSONWriter {
if (this.mode == 'o' || this.mode == 'a') {
try {
if (this.comma && this.mode == 'a') {
this.writer.write(',');
this.writer.append(',');
}
this.writer.write(string);
this.writer.append(string);
} catch (IOException e) {
throw new JSONException(e);
}
@@ -150,20 +149,20 @@ public class JSONWriter {
/**
* End something.
* @param mode Mode
* @param m Mode
* @param c Closing character
* @return this
* @throws JSONException If unbalanced.
*/
private JSONWriter end(char mode, char c) throws JSONException {
if (this.mode != mode) {
throw new JSONException(mode == 'a'
private JSONWriter end(char m, char c) throws JSONException {
if (this.mode != m) {
throw new JSONException(m == 'a'
? "Misplaced endArray."
: "Misplaced endObject.");
}
this.pop(mode);
this.pop(m);
try {
this.writer.write(c);
this.writer.append(c);
} catch (IOException e) {
throw new JSONException(e);
}
@@ -207,10 +206,10 @@ public class JSONWriter {
try {
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
if (this.comma) {
this.writer.write(',');
this.writer.append(',');
}
this.writer.write(JSONObject.quote(string));
this.writer.write(':');
this.writer.append(JSONObject.quote(string));
this.writer.append(':');
this.comma = false;
this.mode = 'o';
return this;

View File

@@ -1,3 +1,5 @@
============================================================================
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -25,7 +25,7 @@ SOFTWARE.
*/
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Properties;
/**
@@ -41,7 +41,7 @@ public class Property {
* @throws JSONException
*/
public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException {
JSONObject jo = new JSONObject();
JSONObject jo = new JSONObject(properties == null ? 0 : properties.size());
if (properties != null && !properties.isEmpty()) {
Enumeration<?> enumProperties = properties.propertyNames();
while(enumProperties.hasMoreElements()) {
@@ -61,10 +61,11 @@ public class Property {
public static Properties toProperties(JSONObject jo) throws JSONException {
Properties properties = new Properties();
if (jo != null) {
Iterator<String> keys = jo.keys();
while (keys.hasNext()) {
String name = keys.next();
properties.put(name, jo.getString(name));
for (final Entry<String, ?> entry : jo.entrySet()) {
Object value = entry.getValue();
if (!JSONObject.NULL.equals(value)) {
properties.put(entry.getKey(), value.toString());
}
}
}
return properties;

11
README
View File

@@ -22,7 +22,7 @@ JSONObject.java: The JSONObject can parse text from a String or a JSONTokener
to produce a map-like object. The object provides methods for manipulating its
contents, and for producing a JSON compliant object serialization.
JSONArray.java: The JSONObject can parse text from a String or a JSONTokener
JSONArray.java: The JSONArray can parse text from a String or a JSONTokener
to produce a vector-like object. The object provides methods for manipulating
its contents, and for producing a JSON compliant array serialization.
@@ -89,8 +89,15 @@ invalid number formats (1.2e6.3) will cause errors as such documents can not be
reliably.
Release history:
20171018 Checkpoint for recent commits.
20160807 Java 1.6 compatability fixed, JSONArray.toList() and JSONObject.toMap(),
20170516 Roll up recent commits.
20160810 Revert code that was breaking opt*() methods.
20160807 This release contains a bug in the JSONObject.opt*() and JSONArray.opt*() methods,
it is not recommended for use.
Java 1.6 compatability fixed, JSONArray.toList() and JSONObject.toMap(),
RFC4180 compatibility, JSONPointer, some exception fixes, optional XML type conversion.
Contains the latest code as of 7 Aug, 2016

161
XML.java
View File

@@ -25,17 +25,17 @@ SOFTWARE.
*/
import java.util.Iterator;
import java.util.Map.Entry;
/**
* This provides static methods to convert an XML text into a JSONObject, and to
* covert a JSONObject into an XML text.
*
* @author JSON.org
* @version 2016-01-30
* @version 2016-08-10
*/
@SuppressWarnings("boxing")
public class XML {
/** The Character '&amp;'. */
public static final Character AMP = '&';
@@ -62,6 +62,46 @@ public class XML {
/** The Character '/'. */
public static final Character SLASH = '/';
/**
* Creates an iterator for navigating Code Points in a string instead of
* characters. Once Java7 support is dropped, this can be replaced with
* <code>
* string.codePoints()
* </code>
* which is available in Java8 and above.
*
* @see <a href=
* "http://stackoverflow.com/a/21791059/6030888">http://stackoverflow.com/a/21791059/6030888</a>
*/
private static Iterable<Integer> codePointIterator(final String string) {
return new Iterable<Integer>() {
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int nextIndex = 0;
private int length = string.length();
@Override
public boolean hasNext() {
return this.nextIndex < this.length;
}
@Override
public Integer next() {
int result = string.codePointAt(this.nextIndex);
this.nextIndex += Character.charCount(result);
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
/**
* Replace special characters with XML escapes:
@@ -71,6 +111,7 @@ public class XML {
* &lt; <small>(less than)</small> is replaced by &amp;lt;
* &gt; <small>(greater than)</small> is replaced by &amp;gt;
* &quot; <small>(double quote)</small> is replaced by &amp;quot;
* &apos; <small>(single quote / apostrophe)</small> is replaced by &amp;apos;
* </pre>
*
* @param string
@@ -79,9 +120,8 @@ public class XML {
*/
public static String escape(String string) {
StringBuilder sb = new StringBuilder(string.length());
for (int i = 0, length = string.length(); i < length; i++) {
char c = string.charAt(i);
switch (c) {
for (final int cp : codePointIterator(string)) {
switch (cp) {
case '&':
sb.append("&amp;");
break;
@@ -98,6 +138,69 @@ public class XML {
sb.append("&apos;");
break;
default:
if (mustEscape(cp)) {
sb.append("&#x");
sb.append(Integer.toHexString(cp));
sb.append(';');
} else {
sb.appendCodePoint(cp);
}
}
}
return sb.toString();
}
/**
* @param cp code point to test
* @return true if the code point is not valid for an XML
*/
private static boolean mustEscape(int cp) {
/* Valid range from https://www.w3.org/TR/REC-xml/#charsets
*
* #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
*
* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
*/
// isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F)
// all ISO control characters are out of range except tabs and new lines
return (Character.isISOControl(cp)
&& cp != 0x9
&& cp != 0xA
&& cp != 0xD
) || !(
// valid the range of acceptable characters that aren't control
(cp >= 0x20 && cp <= 0xD7FF)
|| (cp >= 0xE000 && cp <= 0xFFFD)
|| (cp >= 0x10000 && cp <= 0x10FFFF)
)
;
}
/**
* Removes XML escapes from the string.
*
* @param string
* string to remove escapes from
* @return string with converted entities
*/
public static String unescape(String string) {
StringBuilder sb = new StringBuilder(string.length());
for (int i = 0, length = string.length(); i < length; i++) {
char c = string.charAt(i);
if (c == '&') {
final int semic = string.indexOf(';', i);
if (semic > i) {
final String entity = string.substring(i + 1, semic);
sb.append(XMLTokener.unescapeEntity(entity));
// skip past the entity we just parsed.
i += entity.length() + 1;
} else {
// this shouldn't happen in most cases since the parser
// errors on unclosed entries.
sb.append(c);
}
} else {
// not part of an entity
sb.append(c);
}
}
@@ -227,7 +330,6 @@ public class XML {
if (token == null) {
token = x.nextToken();
}
// attribute = value
if (token instanceof String) {
string = (String) token;
@@ -238,7 +340,7 @@ public class XML {
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string,
keepStrings ? token : JSONObject.stringToValue((String) token));
keepStrings ? ((String)token) : stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
@@ -270,7 +372,7 @@ public class XML {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content",
keepStrings ? token : JSONObject.stringToValue(string));
keepStrings ? string : stringToValue(string));
}
} else if (token == LT) {
@@ -297,14 +399,12 @@ public class XML {
}
/**
* This method has been deprecated in favor of the
* {@link JSONObject.stringToValue(String)} method. Use it instead.
* This method is the same as {@link JSONObject#stringToValue(String)}
* except that this also tries to unescape String values.
*
* @deprecated Use {@link JSONObject#stringToValue(String)} instead.
* @param string String to convert
* @return JSON value of this string or the string
*/
@Deprecated
public static Object stringToValue(String string) {
return JSONObject.stringToValue(string);
}
@@ -381,15 +481,12 @@ public class XML {
* @return A string.
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toString(Object object, String tagName)
public static String toString(final Object object, final String tagName)
throws JSONException {
StringBuilder sb = new StringBuilder();
JSONArray ja;
JSONObject jo;
String key;
Iterator<String> keys;
String string;
Object value;
if (object instanceof JSONObject) {
@@ -402,16 +499,14 @@ public class XML {
// Loop thru the keys.
jo = (JSONObject) object;
keys = jo.keys();
while (keys.hasNext()) {
key = keys.next();
value = jo.opt(key);
for (final Entry<String, ?> entry : jo.entrySet()) {
final String key = entry.getKey();
Object value = entry.getValue();
if (value == null) {
value = "";
} else if (value.getClass().isArray()) {
value = new JSONArray(value);
}
string = value instanceof String ? (String) value : null;
// Emit content in body
if ("content".equals(key)) {
@@ -468,21 +563,19 @@ public class XML {
}
if (object != null) {
if (object.getClass().isArray()) {
object = new JSONArray(object);
}
if (object instanceof JSONArray) {
if (object != null && (object instanceof JSONArray || object.getClass().isArray())) {
if(object.getClass().isArray()) {
ja = new JSONArray(object);
} else {
ja = (JSONArray) object;
for (Object val : ja) {
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// <array> element.
sb.append(toString(val, tagName == null ? "array" : tagName));
}
return sb.toString();
}
for (Object val : ja) {
// XML does not have good support for arrays. If an array
// appears in a place where XML is lacking, synthesize an
// <array> element.
sb.append(toString(val, tagName == null ? "array" : tagName));
}
return sb.toString();
}
string = (object == null) ? "null" : escape(object.toString());

View File

@@ -64,11 +64,8 @@ public class XMLTokener extends JSONTokener {
char c;
int i;
StringBuilder sb = new StringBuilder();
for (;;) {
while (more()) {
c = next();
if (end()) {
throw syntaxError("Unclosed CDATA");
}
sb.append(c);
i = sb.length() - 3;
if (i >= 0 && sb.charAt(i) == ']' &&
@@ -77,6 +74,7 @@ public class XMLTokener extends JSONTokener {
return sb.toString();
}
}
throw syntaxError("Unclosed CDATA");
}
@@ -103,7 +101,10 @@ public class XMLTokener extends JSONTokener {
}
sb = new StringBuilder();
for (;;) {
if (c == '<' || c == 0) {
if (c == 0) {
return sb.toString().trim();
}
if (c == '<') {
back();
return sb.toString().trim();
}
@@ -137,8 +138,37 @@ public class XMLTokener extends JSONTokener {
}
}
String string = sb.toString();
Object object = entity.get(string);
return object != null ? object : ampersand + string + ";";
return unescapeEntity(string);
}
/**
* Unescapes an XML entity encoding;
* @param e entity (only the actual entity value, not the preceding & or ending ;
* @return
*/
static String unescapeEntity(String e) {
// validate
if (e == null || e.isEmpty()) {
return "";
}
// if our entity is an encoded unicode point, parse it.
if (e.charAt(0) == '#') {
int cp;
if (e.charAt(1) == 'x') {
// hex encoded unicode
cp = Integer.parseInt(e.substring(2), 16);
} else {
// decimal encoded unicode
cp = Integer.parseInt(e.substring(1));
}
return new String(new int[] {cp},0,1);
}
Character knownEntity = entity.get(e);
if(knownEntity==null) {
// we don't know the entity so keep it encoded
return '&' + e + ';';
}
return knownEntity.toString();
}