Skip to content

Commit 722003d

Browse files
authored
Merge pull request stleary#350 from johnjaylward/AndroidSupport
Updates for supporting the Android API
2 parents cdf3cf7 + 057e0c7 commit 722003d

File tree

9 files changed

+207
-101
lines changed

9 files changed

+207
-101
lines changed

CookieList.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.json;
22

3-
import java.util.Map.Entry;
4-
53
/*
64
Copyright (c) 2002 JSON.org
75
@@ -24,7 +22,7 @@ of this software and associated documentation files (the "Software"), to deal
2422
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2523
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2624
SOFTWARE.
27-
*/
25+
*/
2826

2927
/**
3028
* Convert a web browser cookie list string to a JSONObject and back.
@@ -69,17 +67,17 @@ public static JSONObject toJSONObject(String string) throws JSONException {
6967
*/
7068
public static String toString(JSONObject jo) throws JSONException {
7169
boolean b = false;
72-
StringBuilder sb = new StringBuilder();
73-
for (final Entry<String,?> entry : jo.entrySet()) {
74-
final String key = entry.getKey();
75-
final Object value = entry.getValue();
70+
final StringBuilder sb = new StringBuilder();
71+
// Don't use the new entrySet API to maintain Android support
72+
for (final String key : jo.keySet()) {
73+
final Object value = jo.opt(key);
7674
if (!JSONObject.NULL.equals(value)) {
7775
if (b) {
7876
sb.append(';');
7977
}
8078
sb.append(Cookie.escape(key));
8179
sb.append("=");
82-
sb.append(Cookie.escape(value.toString()));
80+
sb.append(Cookie.escape(value.toString()));
8381
b = true;
8482
}
8583
}

HTTP.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ of this software and associated documentation files (the "Software"), to deal
2525
*/
2626

2727
import java.util.Locale;
28-
import java.util.Map.Entry;
2928

3029
/**
3130
* Convert an HTTP header to a JSONObject and back.
@@ -145,11 +144,12 @@ public static String toString(JSONObject jo) throws JSONException {
145144
throw new JSONException("Not enough material for an HTTP header.");
146145
}
147146
sb.append(CRLF);
148-
for (final Entry<String,?> entry : jo.entrySet()) {
149-
final String key = entry.getKey();
147+
// Don't use the new entrySet API to maintain Android support
148+
for (final String key : jo.keySet()) {
149+
String value = jo.optString(key);
150150
if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
151151
!"Reason-Phrase".equals(key) && !"Method".equals(key) &&
152-
!"Request-URI".equals(key) && !JSONObject.NULL.equals(entry.getValue())) {
152+
!"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) {
153153
sb.append(key);
154154
sb.append(": ");
155155
sb.append(jo.optString(key));

JSONML.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.json;
22

3-
import java.util.Map.Entry;
4-
53
/*
64
Copyright (c) 2008 JSON.org
75
@@ -416,10 +414,10 @@ public static String toString(JSONArray ja) throws JSONException {
416414

417415
// Emit the attributes
418416

419-
for (final Entry<String, ?> entry : jo.entrySet()) {
420-
final String key = entry.getKey();
417+
// Don't use the new entrySet API to maintain Android support
418+
for (final String key : jo.keySet()) {
419+
final Object value = jo.opt(key);
421420
XML.noSpace(key);
422-
final Object value = entry.getValue();
423421
if (value != null) {
424422
sb.append(' ');
425423
sb.append(XML.escape(key));
@@ -495,11 +493,11 @@ public static String toString(JSONObject jo) throws JSONException {
495493

496494
//Emit the attributes
497495

498-
for (final Entry<String, ?> entry : jo.entrySet()) {
499-
final String key = entry.getKey();
496+
// Don't use the new entrySet API to maintain Android support
497+
for (final String key : jo.keySet()) {
500498
if (!"tagName".equals(key) && !"childNodes".equals(key)) {
501499
XML.noSpace(key);
502-
value = entry.getValue();
500+
value = jo.opt(key);
503501
if (value != null) {
504502
sb.append(' ');
505503
sb.append(XML.escape(key));

JSONObject.java

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,8 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
19501950
* A String.
19511951
* @return A simple JSON value.
19521952
*/
1953+
// Changes to this method must be copied to the corresponding method in
1954+
// the XML class to keep full support for Android
19531955
public static Object stringToValue(String string) {
19541956
if (string.equals("")) {
19551957
return string;
@@ -2120,55 +2122,11 @@ public String toString(int indentFactor) throws JSONException {
21202122
* If the value is or contains an invalid number.
21212123
*/
21222124
public static String valueToString(Object value) throws JSONException {
2123-
if (value == null || value.equals(null)) {
2124-
return "null";
2125-
}
2126-
if (value instanceof JSONString) {
2127-
Object object;
2128-
try {
2129-
object = ((JSONString) value).toJSONString();
2130-
} catch (Exception e) {
2131-
throw new JSONException(e);
2132-
}
2133-
if (object instanceof String) {
2134-
return (String) object;
2135-
}
2136-
throw new JSONException("Bad value from toJSONString: " + object);
2137-
}
2138-
if (value instanceof Number) {
2139-
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
2140-
final String numberAsString = numberToString((Number) value);
2141-
try {
2142-
// Use the BigDecimal constructor for it's parser to validate the format.
2143-
@SuppressWarnings("unused")
2144-
BigDecimal unused = new BigDecimal(numberAsString);
2145-
// Close enough to a JSON number that we will return it unquoted
2146-
return numberAsString;
2147-
} catch (NumberFormatException ex){
2148-
// The Number value is not a valid JSON number.
2149-
// Instead we will quote it as a string
2150-
return quote(numberAsString);
2151-
}
2152-
}
2153-
if (value instanceof Boolean || value instanceof JSONObject
2154-
|| value instanceof JSONArray) {
2155-
return value.toString();
2156-
}
2157-
if (value instanceof Map) {
2158-
Map<?, ?> map = (Map<?, ?>) value;
2159-
return new JSONObject(map).toString();
2160-
}
2161-
if (value instanceof Collection) {
2162-
Collection<?> coll = (Collection<?>) value;
2163-
return new JSONArray(coll).toString();
2164-
}
2165-
if (value.getClass().isArray()) {
2166-
return new JSONArray(value).toString();
2167-
}
2168-
if(value instanceof Enum<?>){
2169-
return quote(((Enum<?>)value).name());
2170-
}
2171-
return quote(value.toString());
2125+
// moves the implementation to JSONWriter as:
2126+
// 1. It makes more sense to be part of the writer class
2127+
// 2. For Android support this method is not available. By implementing it in the Writer
2128+
// Android users can use the writer with the built in Android JSONObject implementation.
2129+
return JSONWriter.valueToString(value);
21722130
}
21732131

21742132
/**

JSONPointer.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.io.UnsupportedEncodingException;
66
import java.net.URLDecoder;
77
import java.net.URLEncoder;
8-
import java.util.*;
8+
import java.util.ArrayList;
9+
import java.util.Collections;
10+
import java.util.List;
911

1012
/*
1113
Copyright (c) 2002 JSON.org
@@ -181,7 +183,7 @@ private String unescape(String token) {
181183
* @return the result of the evaluation
182184
* @throws JSONPointerException if an error occurs during evaluation
183185
*/
184-
public Object queryFrom(Object document) {
186+
public Object queryFrom(Object document) throws JSONPointerException {
185187
if (this.refTokens.isEmpty()) {
186188
return document;
187189
}
@@ -205,18 +207,21 @@ public Object queryFrom(Object document) {
205207
* @param current the JSONArray to be evaluated
206208
* @param indexToken the array index in string form
207209
* @return the matched object. If no matching item is found a
208-
* JSONPointerException is thrown
210+
* @throws JSONPointerException is thrown if the index is out of bounds
209211
*/
210-
@SuppressWarnings("boxing")
211-
private Object readByIndexToken(Object current, String indexToken) {
212+
private Object readByIndexToken(Object current, String indexToken) throws JSONPointerException {
212213
try {
213214
int index = Integer.parseInt(indexToken);
214215
JSONArray currentArr = (JSONArray) current;
215216
if (index >= currentArr.length()) {
216217
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
217218
currentArr.length()));
218219
}
219-
return currentArr.get(index);
220+
try {
221+
return currentArr.get(index);
222+
} catch (JSONException e) {
223+
throw new JSONPointerException("Error reading value at index position " + index, e);
224+
}
220225
} catch (NumberFormatException e) {
221226
throw new JSONPointerException(format("%s is not an array index", indexToken), e);
222227
}

JSONWriter.java

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package org.json;
22

33
import java.io.IOException;
4+
import java.math.BigDecimal;
5+
import java.util.Collection;
6+
import java.util.Map;
47

58
/*
69
Copyright (c) 2006 JSON.org
@@ -117,6 +120,9 @@ private JSONWriter append(String string) throws JSONException {
117120
}
118121
this.writer.append(string);
119122
} catch (IOException e) {
123+
// Android as of API 25 does not support this exception constructor
124+
// however we won't worry about it. If an exception is happening here
125+
// it will just throw a "Method not found" exception instead.
120126
throw new JSONException(e);
121127
}
122128
if (this.mode == 'o') {
@@ -164,6 +170,9 @@ private JSONWriter end(char m, char c) throws JSONException {
164170
try {
165171
this.writer.append(c);
166172
} catch (IOException e) {
173+
// Android as of API 25 does not support this exception constructor
174+
// however we won't worry about it. If an exception is happening here
175+
// it will just throw a "Method not found" exception instead.
167176
throw new JSONException(e);
168177
}
169178
this.comma = true;
@@ -204,7 +213,12 @@ public JSONWriter key(String string) throws JSONException {
204213
}
205214
if (this.mode == 'k') {
206215
try {
207-
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
216+
JSONObject topObject = this.stack[this.top - 1];
217+
// don't use the built in putOnce method to maintain Android support
218+
if(topObject.has(string)) {
219+
throw new JSONException("Duplicate key \"" + string + "\"");
220+
}
221+
topObject.put(string, true);
208222
if (this.comma) {
209223
this.writer.append(',');
210224
}
@@ -214,6 +228,9 @@ public JSONWriter key(String string) throws JSONException {
214228
this.mode = 'o';
215229
return this;
216230
} catch (IOException e) {
231+
// Android as of API 25 does not support this exception constructor
232+
// however we won't worry about it. If an exception is happening here
233+
// it will just throw a "Method not found" exception instead.
217234
throw new JSONException(e);
218235
}
219236
}
@@ -280,6 +297,81 @@ private void push(JSONObject jo) throws JSONException {
280297
this.top += 1;
281298
}
282299

300+
/**
301+
* Make a JSON text of an Object value. If the object has an
302+
* value.toJSONString() method, then that method will be used to produce the
303+
* JSON text. The method is required to produce a strictly conforming text.
304+
* If the object does not contain a toJSONString method (which is the most
305+
* common case), then a text will be produced by other means. If the value
306+
* is an array or Collection, then a JSONArray will be made from it and its
307+
* toJSONString method will be called. If the value is a MAP, then a
308+
* JSONObject will be made from it and its toJSONString method will be
309+
* called. Otherwise, the value's toString method will be called, and the
310+
* result will be quoted.
311+
*
312+
* <p>
313+
* Warning: This method assumes that the data structure is acyclical.
314+
*
315+
* @param value
316+
* The value to be serialized.
317+
* @return a printable, displayable, transmittable representation of the
318+
* object, beginning with <code>{</code>&nbsp;<small>(left
319+
* brace)</small> and ending with <code>}</code>&nbsp;<small>(right
320+
* brace)</small>.
321+
* @throws JSONException
322+
* If the value is or contains an invalid number.
323+
*/
324+
public static String valueToString(Object value) throws JSONException {
325+
if (value == null || value.equals(null)) {
326+
return "null";
327+
}
328+
if (value instanceof JSONString) {
329+
Object object;
330+
try {
331+
object = ((JSONString) value).toJSONString();
332+
} catch (Exception e) {
333+
throw new JSONException(e);
334+
}
335+
if (object instanceof String) {
336+
return (String) object;
337+
}
338+
throw new JSONException("Bad value from toJSONString: " + object);
339+
}
340+
if (value instanceof Number) {
341+
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
342+
final String numberAsString = JSONObject.numberToString((Number) value);
343+
try {
344+
// Use the BigDecimal constructor for it's parser to validate the format.
345+
@SuppressWarnings("unused")
346+
BigDecimal unused = new BigDecimal(numberAsString);
347+
// Close enough to a JSON number that we will return it unquoted
348+
return numberAsString;
349+
} catch (NumberFormatException ex){
350+
// The Number value is not a valid JSON number.
351+
// Instead we will quote it as a string
352+
return JSONObject.quote(numberAsString);
353+
}
354+
}
355+
if (value instanceof Boolean || value instanceof JSONObject
356+
|| value instanceof JSONArray) {
357+
return value.toString();
358+
}
359+
if (value instanceof Map) {
360+
Map<?, ?> map = (Map<?, ?>) value;
361+
return new JSONObject(map).toString();
362+
}
363+
if (value instanceof Collection) {
364+
Collection<?> coll = (Collection<?>) value;
365+
return new JSONArray(coll).toString();
366+
}
367+
if (value.getClass().isArray()) {
368+
return new JSONArray(value).toString();
369+
}
370+
if(value instanceof Enum<?>){
371+
return JSONObject.quote(((Enum<?>)value).name());
372+
}
373+
return JSONObject.quote(value.toString());
374+
}
283375

284376
/**
285377
* Append either the value <code>true</code> or the value
@@ -321,6 +413,6 @@ public JSONWriter value(long l) throws JSONException {
321413
* @throws JSONException If the value is out of sequence.
322414
*/
323415
public JSONWriter value(Object object) throws JSONException {
324-
return this.append(JSONObject.valueToString(object));
416+
return this.append(valueToString(object));
325417
}
326418
}

Property.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ of this software and associated documentation files (the "Software"), to deal
2525
*/
2626

2727
import java.util.Enumeration;
28-
import java.util.Map.Entry;
2928
import java.util.Properties;
3029

3130
/**
@@ -41,7 +40,9 @@ public class Property {
4140
* @throws JSONException
4241
*/
4342
public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException {
44-
JSONObject jo = new JSONObject(properties == null ? 0 : properties.size());
43+
// can't use the new constructor for Android support
44+
// JSONObject jo = new JSONObject(properties == null ? 0 : properties.size());
45+
JSONObject jo = new JSONObject();
4546
if (properties != null && !properties.isEmpty()) {
4647
Enumeration<?> enumProperties = properties.propertyNames();
4748
while(enumProperties.hasMoreElements()) {
@@ -61,10 +62,11 @@ public static JSONObject toJSONObject(java.util.Properties properties) throws JS
6162
public static Properties toProperties(JSONObject jo) throws JSONException {
6263
Properties properties = new Properties();
6364
if (jo != null) {
64-
for (final Entry<String, ?> entry : jo.entrySet()) {
65-
Object value = entry.getValue();
65+
// Don't use the new entrySet API to maintain Android support
66+
for (final String key : jo.keySet()) {
67+
Object value = jo.opt(key);
6668
if (!JSONObject.NULL.equals(value)) {
67-
properties.put(entry.getKey(), value.toString());
69+
properties.put(key, value.toString());
6870
}
6971
}
7072
}

0 commit comments

Comments
 (0)