50 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
John J. Aylward
ae1e9e2b6a fix spelling in javadoc comment 2017-04-03 11:59:36 -04:00
14 changed files with 1118 additions and 386 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() != '\"')
{
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,8 +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.
@@ -126,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"));
@@ -147,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

@@ -154,8 +154,10 @@ public class JSONArray implements Iterable<Object> {
* A Collection.
*/
public JSONArray(Collection<?> collection) {
if (collection == null) {
this.myArrayList = new ArrayList<Object>();
if (collection != null) {
} 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();
}
/**
@@ -244,7 +247,50 @@ public class JSONArray implements Iterable<Object> {
return object instanceof Number ? ((Number) object).doubleValue()
: Double.parseDouble((String) object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.");
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);
}
}
@@ -266,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;
}
@@ -289,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);
}
}
@@ -309,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);
}
}
@@ -328,7 +373,7 @@ public class JSONArray implements Iterable<Object> {
return object instanceof Number ? ((Number) object).intValue()
: Integer.parseInt((String) object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.");
throw new JSONException("JSONArray[" + index + "] is not a number.", e);
}
}
@@ -384,7 +429,7 @@ public class JSONArray implements Iterable<Object> {
return object instanceof Number ? ((Number) object).longValue()
: Long.parseLong((String) object);
} catch (Exception e) {
throw new JSONException("JSONArray[" + index + "] is not a number.");
throw new JSONException("JSONArray[" + index + "] is not a number.", e);
}
}
@@ -453,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) {
@@ -518,12 +563,64 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public double optDouble(int index, double defaultValue) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof Number){
return ((Number) val).doubleValue();
}
if (val instanceof String) {
try {
return this.getDouble(index);
return Double.parseDouble((String) val);
} catch (Exception e) {
return defaultValue;
}
}
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;
}
/**
* Get the optional int value associated with an index. Zero is returned if
@@ -550,12 +647,23 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public int optInt(int index, int defaultValue) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof Number){
return ((Number) val).intValue();
}
if (val instanceof String) {
try {
return this.getInt(index);
return new BigDecimal(val.toString()).intValue();
} catch (Exception e) {
return defaultValue;
}
}
return defaultValue;
}
/**
* Get the enum value associated with a key.
@@ -615,8 +723,29 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public BigInteger optBigInteger(int index, BigInteger defaultValue) {
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 this.getBigInteger(index);
final String valStr = val.toString();
if(JSONObject.isDecimalNotation(valStr)) {
return new BigDecimal(valStr).toBigInteger();
}
return new BigInteger(valStr);
} catch (Exception e) {
return defaultValue;
}
@@ -634,8 +763,25 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) {
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 this.getBigDecimal(index);
return new BigDecimal(val.toString());
} catch (Exception e) {
return defaultValue;
}
@@ -693,17 +839,73 @@ public class JSONArray implements Iterable<Object> {
* @return The value.
*/
public long optLong(int index, long defaultValue) {
Object val = this.opt(index);
if (JSONObject.NULL.equals(val)) {
return defaultValue;
}
if (val instanceof Number){
return ((Number) val).longValue();
}
if (val instanceof String) {
try {
return this.getLong(index);
return new BigDecimal(val.toString()).longValue();
} catch (Exception e) {
return defaultValue;
}
}
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;
}
/**
* 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.
@@ -951,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);
}
@@ -1022,7 +1230,7 @@ public class JSONArray implements Iterable<Object> {
* Queries and returns a value from this object using {@code jsonPointer}, or
* returns null if the query fails due to a missing key.
*
* @param The JSON pointer
* @param jsonPointer The JSON pointer
* @return the queried value or {@code null}
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
@@ -1064,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;
@@ -1097,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));
}
@@ -1109,12 +1323,14 @@ 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.
*/
@Override
public String toString() {
try {
return this.toString(0);
@@ -1124,8 +1340,23 @@ 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.
@@ -1145,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
@@ -1156,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
*/
@@ -1178,8 +1423,12 @@ public class JSONArray implements Iterable<Object> {
writer.write('[');
if (length == 1) {
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;
@@ -1191,8 +1440,12 @@ public class JSONArray implements Iterable<Object> {
writer.write('\n');
}
JSONObject.indent(writer, 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 ? XML.unescape((String)token) :XML.stringToValue((String)token));
newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token));
token = null;
} else {
newjo.accumulate(attribute, "");
@@ -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() || pointer.equals("#")) {
refTokens = Collections.emptyList();
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,18 +39,26 @@ SOFTWARE.
* @version 2014-05-03
*/
public class JSONTokener {
/** 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;
/** 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;
private Reader reader;
/** 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.
*/
@@ -63,12 +71,13 @@ public class JSONTokener {
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()) {
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.back();
this.reader.reset();
} catch (IOException e) {
throw new JSONException("Unable to read the next character from the stream", e);
}
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;
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,9 +244,12 @@ public class JSONTokener {
public char next(char c) throws JSONException {
char n = this.next();
if (n != c) {
if(n > 0) {
throw this.syntaxError("Expected '" + c + "' and instead saw '" +
n + "'");
}
throw this.syntaxError("Expected '" + c + "' and instead saw ''");
}
return n;
}
@@ -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.
*

View File

@@ -149,18 +149,18 @@ 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.append(c);
} catch (IOException e) {

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;

2
README
View File

@@ -89,6 +89,8 @@ invalid number formats (1.2e6.3) will cause errors as such documents can not be
reliably.
Release history:
20171018 Checkpoint for recent commits.
20170516 Roll up recent commits.
20160810 Revert code that was breaking opt*() methods.

View File

@@ -25,6 +25,7 @@ SOFTWARE.
*/
import java.util.Iterator;
import java.util.Map.Entry;
/**
* This provides static methods to convert an XML text into a JSONObject, and to
@@ -140,7 +141,7 @@ public class XML {
if (mustEscape(cp)) {
sb.append("&#x");
sb.append(Integer.toHexString(cp));
sb.append(";");
sb.append(';');
} else {
sb.appendCodePoint(cp);
}
@@ -190,36 +191,12 @@ public class XML {
final int semic = string.indexOf(';', i);
if (semic > i) {
final String entity = string.substring(i + 1, semic);
if (entity.charAt(0) == '#') {
int cp;
if (entity.charAt(1) == 'x') {
// hex encoded unicode
cp = Integer.parseInt(entity.substring(2), 16);
} else {
// decimal encoded unicode
cp = Integer.parseInt(entity.substring(1));
}
sb.appendCodePoint(cp);
} else {
if ("quot".equalsIgnoreCase(entity)) {
sb.append('"');
} else if ("amp".equalsIgnoreCase(entity)) {
sb.append('&');
} else if ("apos".equalsIgnoreCase(entity)) {
sb.append('\'');
} else if ("lt".equalsIgnoreCase(entity)) {
sb.append('<');
} else if ("gt".equalsIgnoreCase(entity)) {
sb.append('>');
} else {
sb.append('&').append(entity).append(';');
}
}
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 enties.
// errors on unclosed entries.
sb.append(c);
}
} else {
@@ -363,7 +340,7 @@ public class XML {
throw x.syntaxError("Missing value");
}
jsonobject.accumulate(string,
keepStrings ? unescape((String)token) : stringToValue((String) token));
keepStrings ? ((String)token) : stringToValue((String) token));
token = null;
} else {
jsonobject.accumulate(string, "");
@@ -395,7 +372,7 @@ public class XML {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content",
keepStrings ? unescape(string) : stringToValue(string));
keepStrings ? string : stringToValue(string));
}
} else if (token == LT) {
@@ -422,18 +399,14 @@ public class XML {
}
/**
* This method is the same as {@link JSONObject.stringToValue(String)}
* This method is the same as {@link JSONObject#stringToValue(String)}
* except that this also tries to unescape String values.
*
* @param string String to convert
* @return JSON value of this string or the string
*/
public static Object stringToValue(String string) {
Object ret = JSONObject.stringToValue(string);
if(ret instanceof String){
return unescape((String)ret);
}
return ret;
return JSONObject.stringToValue(string);
}
/**
@@ -508,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) {
@@ -529,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)) {
@@ -595,13 +563,12 @@ 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
@@ -610,7 +577,6 @@ public class XML {
}
return sb.toString();
}
}
string = (object == null) ? "null" : escape(object.toString());
return (tagName == null) ? "\"" + string + "\""

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();
}