144 Commits

Author SHA1 Message Date
Sean Leary
5b845f28cf Update README.md
New RFC8259, no changes to in-doc references.
2019-05-08 20:27:25 -05:00
Sean Leary
00e0e6c0a2 Merge pull request #467 from meiskalt7/addConfigurationForXsiNilConversionToNull
add configuration for xsi:nil="true" conversion to null
2019-04-22 08:33:16 -05:00
meiskalt7
d5b278539e add configuration for xsi:nil="true" conversion to null 2019-04-09 19:49:32 +07:00
Sean Leary
12bbe8cd9a Merge pull request #452 from johnjaylward/FixEOF
Adds check for EOF
2018-12-13 09:14:10 -06:00
Sean Leary
09dddb826e Merge pull request #412 from johnjaylward/XmlConfig
Initial implementation of XMLParserConfig object for flexible XML Parsing
2018-12-11 07:26:50 -06:00
John J. Aylward
19e9bb6c07 Adds check for EOF 2018-12-10 11:45:53 -05:00
Sean Leary
fea0aca2ab Update README.md 2018-12-08 19:54:06 -06:00
Sean Leary
1a811f1ada Merge pull request #440 from johnjaylward/FixForBigDecimal
Fixes #438 - Corrections to BigDecimal consistency
2018-10-06 14:51:57 -05:00
John J. Aylward
34cfe6df14 removes duplicate code in number getters 2018-10-04 16:02:14 -04:00
John J. Aylward
71c6dd1e34 remove unneeded casts 2018-10-02 15:33:33 -04:00
John J. Aylward
30c1bd16ba fix javadoc 2018-10-02 15:28:53 -04:00
John J. Aylward
bc347d2c19 cleanup of minor warnings 2018-10-02 15:28:24 -04:00
John J. Aylward
a63fa03062 * Fixes opt/getBigDecimal to be consistent
* Performance: Updates JSONWriter to use a regex to decide if writing as a number is best.
2018-10-02 15:28:24 -04:00
Sean Leary
16225efbdd Merge pull request #432 from johnjaylward/patch-2
Update README.md
2018-08-15 08:32:32 -05:00
johnjaylward
b8a3342eb1 Update README.md
update maven search example.
2018-08-15 09:18:14 -04:00
Sean Leary
37f5bf28e9 Update README.md 2018-08-13 20:46:20 -05:00
Sean Leary
7a17ae0b3e Merge pull request #421 from strkkk/add-emptiness-methods
add isEmpty and isNotEmpty methods
2018-05-26 09:56:23 -05:00
Andrei Paikin
7cad4c3b26 partially revert changes 2018-05-25 22:17:03 +03:00
Andrei_Paikin
05074386d3 change length comparison to isEmpty method 2018-05-21 16:58:13 +03:00
Andrei Paikin
a490ebdb78 add isEmpty and isNotEmpty methods 2018-05-19 09:42:21 +03:00
Sean Leary
3c1535d724 Merge pull request #417 from stleary/fix-double-ctor
fix double ctor in JSONWriter
2018-05-16 08:46:01 -05:00
stleary
a6284df9c7 initial commit 2018-05-02 20:28:45 -05:00
Sean Leary
bfb300835f Merge pull request #411 from johnjaylward/JSONPointerTrailingSlash
Fix for invalid processing of trailing / for JSON Pointer
2018-03-27 07:44:48 -05:00
John J. Aylward
ca9df04539 Initial implementation of XMLParserConfig object for more flexible XML parsing 2018-03-21 22:09:46 -04:00
Sean Leary
06e9ad280f Merge pull request #403 from paulpolushkin/idea-fix
ignore Intellij Idea project files
2018-03-19 19:10:29 -05:00
John J. Aylward
2362c930d1 Fixes #410. Invalid processing of trailing / for JSON Pointer 2018-03-19 09:57:06 -04:00
Sean Leary
2a6b5bacc5 Merge pull request #406 from johnjaylward/FixBeanKeyNameing
Adds annotations to customize field names during Bean serialization
2018-03-14 21:18:23 -05:00
John J. Aylward
a509a28ed4 Cleans up the name check a little to be more permissive on what can be tagged with the new JSONPropertyName annotation.
Also updates the javadoc to reflect the new name allowances
2018-03-11 17:22:05 -04:00
Sean Leary
1c1ef5b211 Merge pull request #405 from johnjaylward/FixNPE
Updates javadoc to match actual exceptions thrown.
2018-03-11 15:57:23 -05:00
John J. Aylward
74b9a60f98 Adds annotation to support custom field names during Bean serialization 2018-03-11 16:28:24 -04:00
John J. Aylward
b63b976acb Updates javadoc to match actual exceptions thrown.
Also optimizes some boxing statements and returns.
2018-03-07 12:35:56 -05:00
Pavel Polushkin
97e180444d ignore Intellij Idea project files 2018-02-25 13:08:58 +03:00
Sean Leary
d402a99fd8 Merge pull request #400 from foldvari/master
XML toJSONObject(Reader reader)
2018-02-10 11:09:26 -06:00
György Földvári
7073bc8c47 XML toJSONObject(Readre reader) 2018-02-04 18:43:35 +01:00
Sean Leary
61cdfefc36 Update README.md 2018-01-30 19:46:24 -06:00
Sean Leary
fbad2d0017 Merge pull request #392 from philippgille/patch-1
Remove wrong apostrophe
2018-01-20 03:39:07 -06:00
Philipp Gillé
15719886f7 Remove wrong apostrophe 2018-01-17 18:41:48 +01:00
Sean Leary
ca45b02ffc Merge pull request #381 from fleipold/maven-badge
Adding maven badge to readme
2018-01-14 10:18:46 -06:00
Felix Leipold
b6efbabc32 Making links markdown links 2017-11-17 12:47:49 +01:00
Felix Leipold
9eb8c27724 Marking up class and method names as inline code 2017-11-17 12:33:50 +01:00
Felix Leipold
195963357c Make file names bold 2017-11-17 12:24:17 +01:00
Felix Leipold
28efdb4860 Moving Badge below title 2017-11-17 12:24:03 +01:00
Felix Leipold
c88653ca2e History with fixed font 2017-11-14 17:23:53 +01:00
Felix Leipold
b3068d9fe4 Marking file and class names with single quotes 2017-11-14 17:23:52 +01:00
Felix Leipold
dba4afd0cf Adding maven repo badge 2017-11-14 17:23:36 +01:00
Felix Leipold
26160e1619 Remove trailing whitespace 2017-11-14 17:23:36 +01:00
Felix Leipold
b7e2eee4d6 Renaming README to README.md 2017-11-14 17:23:36 +01:00
Sean Leary
28e09dc493 Merge pull request #380 from johnjaylward/FixFalsePositiveSimilar
Fix for false positives in similar functions
2017-11-11 16:12:06 -06:00
John J. Aylward
4a4b2db8c1 fix for issue #379 2017-11-06 10:28:28 -05:00
Sean Leary
f16682bf44 Merge pull request #375 from johnjaylward/FixExceptionWrapping
fixes wrapped exceptions
2017-11-02 21:42:29 -05:00
John J. Aylward
18952b5ac0 fixes wrapped exceptions 2017-11-02 22:32:24 -04:00
Sean Leary
d2a66a4287 Merge pull request #373 from johnjaylward/UnclosedJSONArray
Fixes Unclosed json array stack overflow
2017-11-02 20:02:26 -05:00
Sean Leary
722003d479 Merge pull request #350 from johnjaylward/AndroidSupport
Updates for supporting the Android API
2017-10-30 11:33:10 -05:00
John J. Aylward
ed8745cd63 fixes #372.
Corrects behavior of unclosed arrays
2017-10-30 08:18:59 -04:00
John J. Aylward
057e0c75ca Merge remote-tracking branch 'origin/master' into AndroidSupport 2017-10-27 13:28:20 -04:00
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
John J. Aylward
3997a90d58 update constructor call to match Android implementation 2017-07-07 12:24:27 -04:00
John J. Aylward
1736a60ffe adds comment for the API change 2017-07-07 12:17:45 -04:00
John J. Aylward
e8b1b66888 Updates for supporting the Android API 2017-07-07 12:17:39 -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
20 changed files with 2373 additions and 872 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
# ignore eclipse project files
.project
.classpath
# ignore Intellij Idea project files
.idea
*.iml

View File

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

@@ -24,8 +24,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 +37,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 +67,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)) {
final StringBuilder sb = new StringBuilder();
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
final Object value = jo.opt(key);
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,7 @@ 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;
/**
* Convert an HTTP header to a JSONObject and back.
@@ -74,7 +74,7 @@ public class HTTP {
String token;
token = x.nextToken();
if (token.toUpperCase().startsWith("HTTP")) {
if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
// Response
@@ -125,8 +125,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 +144,15 @@ 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);
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
String value = jo.optString(key);
if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
!"Reason-Phrase".equals(key) && !"Method".equals(key) &&
!"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) {
sb.append(key);
sb.append(": ");
sb.append(jo.getString(string));
sb.append(jo.optString(key));
sb.append(CRLF);
}
}

View File

@@ -36,6 +36,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A JSONArray is an ordered sequence of values. Its external text form is a
* string wrapped in square brackets with commas separating the values. The
@@ -78,7 +79,7 @@ import java.util.Map;
* </ul>
*
* @author JSON.org
* @version 2016-07-19
* @version 2016-08/15
*/
public class JSONArray implements Iterable<Object> {
@@ -107,7 +108,13 @@ public class JSONArray implements Iterable<Object> {
if (x.nextClean() != '[') {
throw x.syntaxError("A JSONArray text must start with '['");
}
if (x.nextClean() != ']') {
char nextChar = x.nextClean();
if (nextChar == 0) {
// array is unclosed. No ']' found, instead EOF
throw x.syntaxError("Expected a ',' or ']'");
}
if (nextChar != ']') {
x.back();
for (;;) {
if (x.nextClean() == ',') {
@@ -118,8 +125,16 @@ public class JSONArray implements Iterable<Object> {
this.myArrayList.add(x.nextValue());
}
switch (x.nextClean()) {
case 0:
// array is unclosed. No ']' found, instead EOF
throw x.syntaxError("Expected a ',' or ']'");
case ',':
if (x.nextClean() == ']') {
nextChar = x.nextClean();
if (nextChar == 0) {
// array is unclosed. No ']' found, instead EOF
throw x.syntaxError("Expected a ',' or ']'");
}
if (nextChar == ']') {
return;
}
x.back();
@@ -154,8 +169,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));
}
@@ -163,15 +180,22 @@ public class JSONArray implements Iterable<Object> {
}
/**
* Construct a JSONArray from an array
* Construct a JSONArray from an array.
*
* @param array
* Array. If the parameter passed is null, or not an array, an
* exception will be thrown.
*
* @throws JSONException
* If not an array.
* If not an array or if an array value is non-finite number.
* @throws NullPointerException
* Thrown if the array parameter is null.
*/
public JSONArray(Object array) throws JSONException {
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 +207,7 @@ public class JSONArray implements Iterable<Object> {
@Override
public Iterator<Object> iterator() {
return myArrayList.iterator();
return this.myArrayList.iterator();
}
/**
@@ -239,22 +263,50 @@ public class JSONArray implements Iterable<Object> {
* to a number.
*/
public double getDouble(int index) throws JSONException {
return this.getNumber(index).doubleValue();
}
/**
* 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 {
return this.getNumber(index).floatValue();
}
/**
* 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).doubleValue();
} else if (object instanceof String) {
return Double.parseDouble((String) object);
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.");
}
/**
* Get the enum value associated with an index.
*
* @param <E>
* Enum Type
* @param clazz
* The type of enum to retrieve.
* @param index
@@ -270,15 +322,17 @@ 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;
}
/**
* Get the BigDecimal value associated with an index.
* Get the BigDecimal value associated with an index. If the value is float
* or double, the the {@link BigDecimal#BigDecimal(double)} constructor
* will be used. See notes on the constructor for conversion issues that
* may arise.
*
* @param index
* The index must be between 0 and length() - 1.
@@ -289,12 +343,12 @@ public class JSONArray implements Iterable<Object> {
*/
public BigDecimal getBigDecimal (int index) throws JSONException {
Object object = this.get(index);
try {
return new BigDecimal(object.toString());
} catch (Exception e) {
BigDecimal val = JSONObject.objectToBigDecimal(object, null);
if(val == null) {
throw new JSONException("JSONArray[" + index +
"] could not convert to BigDecimal.");
"] could not convert to BigDecimal ("+ object + ").");
}
return val;
}
/**
@@ -309,12 +363,12 @@ public class JSONArray implements Iterable<Object> {
*/
public BigInteger getBigInteger (int index) throws JSONException {
Object object = this.get(index);
try {
return new BigInteger(object.toString());
} catch (Exception e) {
BigInteger val = JSONObject.objectToBigInteger(object, null);
if(val == null) {
throw new JSONException("JSONArray[" + index +
"] could not convert to BigInteger.");
"] could not convert to BigDecimal ("+ object + ").");
}
return val;
}
/**
@@ -327,17 +381,7 @@ public class JSONArray implements Iterable<Object> {
* If the key is not found or if the value is not a number.
*/
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);
}
} catch (Exception e) {
}
throw new JSONException("JSONArray[" + index + "] is not a number.");
return this.getNumber(index).intValue();
}
/**
@@ -387,17 +431,7 @@ public class JSONArray implements Iterable<Object> {
* to a number.
*/
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);
}
} catch (Exception e) {
}
throw new JSONException("JSONArray[" + index + "] is not a number.");
return this.getNumber(index).longValue();
}
/**
@@ -418,11 +452,11 @@ public class JSONArray implements Iterable<Object> {
}
/**
* Determine if the value is null.
* Determine if the value is <code>null</code>.
*
* @param index
* The index must be between 0 and length() - 1.
* @return true if the value at the index is null, or if there is no value.
* @return true if the value at the index is <code>null</code>, or if there is no value.
*/
public boolean isNull(int index) {
return JSONObject.NULL.equals(this.opt(index));
@@ -441,13 +475,16 @@ public class JSONArray implements Iterable<Object> {
*/
public String join(String separator) throws JSONException {
int len = this.length();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i += 1) {
if (i > 0) {
sb.append(separator);
if (len == 0) {
return "";
}
sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
StringBuilder sb = new StringBuilder(
JSONObject.valueToString(this.myArrayList.get(0)));
for (int i = 1; i < len; i++) {
sb.append(separator)
.append(JSONObject.valueToString(this.myArrayList.get(i)));
}
return sb.toString();
}
@@ -465,7 +502,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 +535,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,21 +567,52 @@ 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)) {
final Number val = this.optNumber(index, null);
if (val == null) {
return defaultValue;
}
try {
if (object instanceof Number) {
return ((Number) object).doubleValue();
} else if (object instanceof String) {
return Double.parseDouble((String) object);
final double doubleValue = val.doubleValue();
// if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
// return defaultValue;
// }
return doubleValue;
}
} catch (Exception e) {
/**
* 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) {
final Number val = this.optNumber(index, null);
if (val == null) {
return defaultValue;
}
final float floatValue = val.floatValue();
// if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
// return floatValue;
// }
return floatValue;
}
/**
* Get the optional int value associated with an index. Zero is returned if
@@ -580,25 +639,18 @@ 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)) {
final Number val = this.optNumber(index, null);
if (val == null) {
return defaultValue;
}
try {
if (object instanceof Number) {
return ((Number) object).intValue();
} else if (object instanceof String) {
return Integer.parseInt((String) object);
}
} catch (Exception e) {
}
return defaultValue;
return val.intValue();
}
/**
* Get the enum value associated with a key.
*
* @param <E>
* Enum Type
* @param clazz
* The type of enum to retrieve.
* @param index
@@ -612,6 +664,8 @@ public class JSONArray implements Iterable<Object> {
/**
* Get the enum value associated with a key.
*
* @param <E>
* Enum Type
* @param clazz
* The type of enum to retrieve.
* @param index
@@ -641,7 +695,6 @@ public class JSONArray implements Iterable<Object> {
}
}
/**
* Get the optional BigInteger value associated with an index. The
* defaultValue is returned if there is no value for the index, or if the
@@ -654,21 +707,17 @@ 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)) {
return defaultValue;
}
try {
return new BigInteger(object.toString());
} catch (Exception e) {
return defaultValue;
}
Object val = this.opt(index);
return JSONObject.objectToBigInteger(val, defaultValue);
}
/**
* Get the optional BigDecimal 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.
* value is not a number and cannot be converted to a number. If the value
* is float or double, the the {@link BigDecimal#BigDecimal(double)}
* constructor will be used. See notes on the constructor for conversion
* issues that may arise.
*
* @param index
* The index must be between 0 and length() - 1.
@@ -677,15 +726,8 @@ 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)) {
return defaultValue;
}
try {
return new BigDecimal(object.toString());
} catch (Exception e) {
return defaultValue;
}
Object val = this.opt(index);
return JSONObject.objectToBigDecimal(val, defaultValue);
}
/**
@@ -740,18 +782,54 @@ 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)) {
final Number val = this.optNumber(index, null);
if (val == null) {
return defaultValue;
}
try {
if (object instanceof Number) {
return ((Number) object).longValue();
} else if (object instanceof String) {
return Long.parseLong((String) object);
return val.longValue();
}
} catch (Exception e) {
/**
* 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 +837,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.
@@ -793,8 +871,7 @@ public class JSONArray implements Iterable<Object> {
* @return this.
*/
public JSONArray put(boolean value) {
this.put(value ? Boolean.TRUE : Boolean.FALSE);
return this;
return this.put(value ? Boolean.TRUE : Boolean.FALSE);
}
/**
@@ -804,10 +881,11 @@ public class JSONArray implements Iterable<Object> {
* @param value
* A Collection value.
* @return this.
* @throws JSONException
* If the value is non-finite number.
*/
public JSONArray put(Collection<?> value) {
this.put(new JSONArray(value));
return this;
return this.put(new JSONArray(value));
}
/**
@@ -815,15 +893,25 @@ public class JSONArray implements Iterable<Object> {
*
* @param value
* A double value.
* @return this.
* @throws JSONException
* if the value is not finite.
* @return this.
*/
public JSONArray put(double value) throws JSONException {
Double d = new Double(value);
JSONObject.testValidity(d);
this.put(d);
return this;
return this.put(Double.valueOf(value));
}
/**
* Append a float value. This increases the array's length by one.
*
* @param value
* A float value.
* @return this.
* @throws JSONException
* if the value is not finite.
*/
public JSONArray put(float value) throws JSONException {
return this.put(Float.valueOf(value));
}
/**
@@ -834,8 +922,7 @@ public class JSONArray implements Iterable<Object> {
* @return this.
*/
public JSONArray put(int value) {
this.put(new Integer(value));
return this;
return this.put(Integer.valueOf(value));
}
/**
@@ -846,8 +933,7 @@ public class JSONArray implements Iterable<Object> {
* @return this.
*/
public JSONArray put(long value) {
this.put(new Long(value));
return this;
return this.put(Long.valueOf(value));
}
/**
@@ -857,10 +943,13 @@ public class JSONArray implements Iterable<Object> {
* @param value
* A Map value.
* @return this.
* @throws JSONException
* If a value in the map is non-finite number.
* @throws NullPointerException
* If a key in the map is <code>null</code>
*/
public JSONArray put(Map<?, ?> value) {
this.put(new JSONObject(value));
return this;
return this.put(new JSONObject(value));
}
/**
@@ -871,8 +960,11 @@ public class JSONArray implements Iterable<Object> {
* Integer, JSONArray, JSONObject, Long, or String, or the
* JSONObject.NULL object.
* @return this.
* @throws JSONException
* If the value is non-finite number.
*/
public JSONArray put(Object value) {
JSONObject.testValidity(value);
this.myArrayList.add(value);
return this;
}
@@ -891,8 +983,7 @@ public class JSONArray implements Iterable<Object> {
* If the index is negative.
*/
public JSONArray put(int index, boolean value) throws JSONException {
this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
return this;
return this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
}
/**
@@ -905,11 +996,10 @@ public class JSONArray implements Iterable<Object> {
* A Collection value.
* @return this.
* @throws JSONException
* If the index is negative or if the value is not finite.
* If the index is negative or if the value is non-finite.
*/
public JSONArray put(int index, Collection<?> value) throws JSONException {
this.put(index, new JSONArray(value));
return this;
return this.put(index, new JSONArray(value));
}
/**
@@ -923,11 +1013,27 @@ public class JSONArray implements Iterable<Object> {
* A double value.
* @return this.
* @throws JSONException
* If the index is negative or if the value is not finite.
* If the index is negative or if the value is non-finite.
*/
public JSONArray put(int index, double value) throws JSONException {
this.put(index, new Double(value));
return this;
return this.put(index, Double.valueOf(value));
}
/**
* Put or replace a float value. If the index is greater than the length of
* the JSONArray, then null elements will be added as necessary to pad it
* out.
*
* @param index
* The subscript.
* @param value
* A float value.
* @return this.
* @throws JSONException
* If the index is negative or if the value is non-finite.
*/
public JSONArray put(int index, float value) throws JSONException {
return this.put(index, Float.valueOf(value));
}
/**
@@ -944,8 +1050,7 @@ public class JSONArray implements Iterable<Object> {
* If the index is negative.
*/
public JSONArray put(int index, int value) throws JSONException {
this.put(index, new Integer(value));
return this;
return this.put(index, Integer.valueOf(value));
}
/**
@@ -962,8 +1067,7 @@ public class JSONArray implements Iterable<Object> {
* If the index is negative.
*/
public JSONArray put(int index, long value) throws JSONException {
this.put(index, new Long(value));
return this;
return this.put(index, Long.valueOf(value));
}
/**
@@ -978,6 +1082,8 @@ public class JSONArray implements Iterable<Object> {
* @throws JSONException
* If the index is negative or if the the value is an invalid
* number.
* @throws NullPointerException
* If a key in the map is <code>null</code>
*/
public JSONArray put(int index, Map<?, ?> value) throws JSONException {
this.put(index, new JSONObject(value));
@@ -1001,20 +1107,27 @@ public class JSONArray implements Iterable<Object> {
* number.
*/
public JSONArray put(int index, Object value) throws JSONException {
JSONObject.testValidity(value);
if (index < 0) {
throw new JSONException("JSONArray[" + index + "] not found.");
}
if (index < this.length()) {
JSONObject.testValidity(value);
this.myArrayList.set(index, value);
} else {
while (index != this.length()) {
this.put(JSONObject.NULL);
}
this.put(value);
}
return this;
}
if(index == this.length()){
// simple append
return this.put(value);
}
// 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()) {
// we don't need to test validity of NULL objects
this.myArrayList.add(JSONObject.NULL);
}
return this.put(value);
}
/**
* Creates a JSONPointer using an initialization string and tries to
@@ -1036,7 +1149,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 user initialized JSONPointer and tries to
* match it to an item within 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 +1184,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 +1233,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) {
continue;
}
if(valueThis == null) {
return false;
}
if (valueThis instanceof JSONObject) {
if (!((JSONObject)valueThis).similar(valueOther)) {
return false;
@@ -1116,10 +1269,10 @@ public class JSONArray implements Iterable<Object> {
* If any of the names are null.
*/
public JSONObject toJSONObject(JSONArray names) throws JSONException {
if (names == null || names.length() == 0 || this.length() == 0) {
if (names == null || names.isEmpty() || this.isEmpty()) {
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 +1284,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,8 +1301,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.
@@ -1168,8 +1337,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 +1349,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 +1384,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;
@@ -1214,8 +1401,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) {
@@ -1254,4 +1445,14 @@ public class JSONArray implements Iterable<Object> {
}
return results;
}
/**
* Check if JSONArray is empty.
*
* @return true if JSONArray is empty, otherwise false.
*/
public boolean isEmpty() {
return this.myArrayList.isEmpty();
}
}

View File

@@ -24,9 +24,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 +39,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 +172,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 +223,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 +394,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 +414,16 @@ public class JSONML {
// Emit the attributes
keys = jo.keys();
while (keys.hasNext()) {
key = keys.next();
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
final Object value = jo.opt(key);
XML.noSpace(key);
value = jo.optString(key);
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 +475,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 +493,17 @@ public class JSONML {
//Emit the attributes
keys = jo.keys();
while (keys.hasNext()) {
key = keys.next();
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
if (!"tagName".equals(key) && !"childNodes".equals(key)) {
XML.noSpace(key);
value = jo.optString(key);
value = jo.opt(key);
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

@@ -5,7 +5,9 @@ import static java.lang.String.format;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
Copyright (c) 2002 JSON.org
@@ -68,11 +70,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 +89,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 +101,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,30 +136,50 @@ 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>();
int slashIdx = -1;
int prevSlashIdx = 0;
do {
prevSlashIdx = slashIdx + 1;
slashIdx = refs.indexOf('/', prevSlashIdx);
if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) {
// found 2 slashes in a row ( obj//next )
// or single slash at the end of a string ( obj/test/ )
this.refTokens.add("");
} else if (slashIdx >= 0) {
final String token = refs.substring(prevSlashIdx, slashIdx);
this.refTokens.add(unescape(token));
} else {
// last item after separator, or no separator at all.
final String token = refs.substring(prevSlashIdx);
this.refTokens.add(unescape(token));
}
} while (slashIdx >= 0);
// using split does not take into account consecutive separators or "ending nulls"
//for (String token : refs.split("/")) {
// this.refTokens.add(unescape(token));
//}
}
public JSONPointer(List<String> refTokens) {
@@ -180,12 +202,12 @@ public class JSONPointer {
* @return the result of the evaluation
* @throws JSONPointerException if an error occurs during evaluation
*/
public Object queryFrom(Object document) {
if (refTokens.isEmpty()) {
public Object queryFrom(Object document) throws JSONPointerException {
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) {
@@ -204,17 +226,21 @@ public class JSONPointer {
* @param current the JSONArray to be evaluated
* @param indexToken the array index in string form
* @return the matched object. If no matching item is found a
* JSONPointerException is thrown
* @throws JSONPointerException is thrown if the index is out of bounds
*/
private Object readByIndexToken(Object current, String indexToken) {
private Object readByIndexToken(Object current, String indexToken) throws JSONPointerException {
try {
int index = Integer.parseInt(indexToken);
JSONArray currentArr = (JSONArray) current;
if (index >= currentArr.length()) {
throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
currentArr.length()));
throw new JSONPointerException(format("index %s is out of bounds - the array has %d elements", indexToken,
Integer.valueOf(currentArr.length())));
}
try {
return currentArr.get(index);
} catch (JSONException e) {
throw new JSONPointerException("Error reading value at index position " + index, e);
}
} catch (NumberFormatException e) {
throw new JSONPointerException(format("%s is not an array index", indexToken), e);
}
@@ -227,7 +253,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 +281,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();

43
JSONPropertyIgnore.java Normal file
View File

@@ -0,0 +1,43 @@
package org.json;
/*
Copyright (c) 2018 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.
*/
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Retention(RUNTIME)
@Target({METHOD})
/**
* Use this annotation on a getter method to override the Bean name
* parser for Bean -&gt; JSONObject mapping. If this annotation is
* present at any level in the class hierarchy, then the method will
* not be serialized from the bean into the JSONObject.
*/
public @interface JSONPropertyIgnore { }

47
JSONPropertyName.java Normal file
View File

@@ -0,0 +1,47 @@
package org.json;
/*
Copyright (c) 2018 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.
*/
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Retention(RUNTIME)
@Target({METHOD})
/**
* Use this annotation on a getter method to override the Bean name
* parser for Bean -&gt; JSONObject mapping. A value set to empty string <code>""</code>
* will have the Bean parser fall back to the default field name processing.
*/
public @interface JSONPropertyName {
/**
* @return The name of the property as to be used in the JSON Object.
*/
String value();
}

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

@@ -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;
}
@@ -397,7 +448,9 @@ public class JSONTokener {
sb.append(c);
c = this.next();
}
if (!this.eof) {
this.back();
}
string = sb.toString().trim();
if ("".equals(string)) {
@@ -426,13 +479,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 +497,6 @@ public class JSONTokener {
return c;
}
/**
* Make a JSONException to signal a syntax error.
*

View File

@@ -1,7 +1,8 @@
package org.json;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Map;
/*
Copyright (c) 2006 JSON.org
@@ -50,11 +51,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 +89,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,10 +115,13 @@ 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) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e);
}
if (this.mode == 'o') {
@@ -150,21 +154,24 @@ 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) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e);
}
this.comma = true;
@@ -205,16 +212,24 @@ public class JSONWriter {
}
if (this.mode == 'k') {
try {
this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
if (this.comma) {
this.writer.write(',');
JSONObject topObject = this.stack[this.top - 1];
// don't use the built in putOnce method to maintain Android support
if(topObject.has(string)) {
throw new JSONException("Duplicate key \"" + string + "\"");
}
this.writer.write(JSONObject.quote(string));
this.writer.write(':');
topObject.put(string, true);
if (this.comma) {
this.writer.append(',');
}
this.writer.append(JSONObject.quote(string));
this.writer.append(':');
this.comma = false;
this.mode = 'o';
return this;
} catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e);
}
}
@@ -281,6 +296,77 @@ public class JSONWriter {
this.top += 1;
}
/**
* Make a JSON text of an Object value. If the object has an
* value.toJSONString() method, then that method will be used to produce the
* JSON text. The method is required to produce a strictly conforming text.
* If the object does not contain a toJSONString method (which is the most
* common case), then a text will be produced by other means. If the value
* is an array or Collection, then a JSONArray will be made from it and its
* toJSONString method will be called. If the value is a MAP, then a
* JSONObject will be made from it and its toJSONString method will be
* called. Otherwise, the value's toString method will be called, and the
* result will be quoted.
*
* <p>
* Warning: This method assumes that the data structure is acyclical.
*
* @param value
* The value to be serialized.
* @return a printable, displayable, transmittable representation of the
* object, beginning with <code>{</code>&nbsp;<small>(left
* brace)</small> and ending with <code>}</code>&nbsp;<small>(right
* brace)</small>.
* @throws JSONException
* If the value is or contains an invalid number.
*/
public static String valueToString(Object value) throws JSONException {
if (value == null || value.equals(null)) {
return "null";
}
if (value instanceof JSONString) {
String object;
try {
object = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
if (object != null) {
return object;
}
throw new JSONException("Bad value from toJSONString: " + object);
}
if (value instanceof Number) {
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
final String numberAsString = JSONObject.numberToString((Number) value);
if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
// Close enough to a JSON number that we will return it unquoted
return numberAsString;
}
// The Number value is not a valid JSON number.
// Instead we will quote it as a string
return JSONObject.quote(numberAsString);
}
if (value instanceof Boolean || value instanceof JSONObject
|| value instanceof JSONArray) {
return value.toString();
}
if (value instanceof Map) {
Map<?, ?> map = (Map<?, ?>) value;
return new JSONObject(map).toString();
}
if (value instanceof Collection) {
Collection<?> coll = (Collection<?>) value;
return new JSONArray(coll).toString();
}
if (value.getClass().isArray()) {
return new JSONArray(value).toString();
}
if(value instanceof Enum<?>){
return JSONObject.quote(((Enum<?>)value).name());
}
return JSONObject.quote(value.toString());
}
/**
* Append either the value <code>true</code> or the value
@@ -300,7 +386,7 @@ public class JSONWriter {
* @throws JSONException If the number is not finite.
*/
public JSONWriter value(double d) throws JSONException {
return this.value(new Double(d));
return this.value(Double.valueOf(d));
}
/**
@@ -322,6 +408,6 @@ public class JSONWriter {
* @throws JSONException If the value is out of sequence.
*/
public JSONWriter value(Object object) throws JSONException {
return this.append(JSONObject.valueToString(object));
return this.append(valueToString(object));
}
}

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,6 @@ SOFTWARE.
*/
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Properties;
/**
@@ -41,6 +40,8 @@ public class Property {
* @throws JSONException
*/
public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException {
// can't use the new constructor for Android support
// JSONObject jo = new JSONObject(properties == null ? 0 : properties.size());
JSONObject jo = new JSONObject();
if (properties != null && !properties.isEmpty()) {
Enumeration<?> enumProperties = properties.propertyNames();
@@ -61,10 +62,12 @@ 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));
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
Object value = jo.opt(key);
if (!JSONObject.NULL.equals(value)) {
properties.put(key, value.toString());
}
}
}
return properties;

107
README
View File

@@ -1,107 +0,0 @@
JSON in Java [package org.json]
JSON is a light-weight, language independent, data interchange format.
See http://www.JSON.org/
The files in this package implement JSON encoders/decoders in Java.
It also includes the capability to convert between JSON and XML, HTTP
headers, Cookies, and CDL.
This is a reference implementation. There is a large number of JSON packages
in Java. Perhaps someday the Java community will standardize on one. Until
then, choose carefully.
The license includes this restriction: "The software shall be used for good,
not evil." If your conscience cannot live with that, then choose a different
package.
The package compiles on Java 1.6-1.8.
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
to produce a vector-like object. The object provides methods for manipulating
its contents, and for producing a JSON compliant array serialization.
JSONTokener.java: The JSONTokener breaks a text into a sequence of individual
tokens. It can be constructed from a String, Reader, or InputStream.
JSONException.java: The JSONException is the standard exception type thrown
by this package.
JSONPointer.java: Implementation of
[JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901). Supports
JSON Pointers both in the form of string representation and URI fragment
representation.
JSONString.java: The JSONString interface requires a toJSONString method,
allowing an object to provide its own serialization.
JSONStringer.java: The JSONStringer provides a convenient facility for
building JSON strings.
JSONWriter.java: The JSONWriter provides a convenient facility for building
JSON text through a writer.
CDL.java: CDL provides support for converting between JSON and comma
delimited lists.
Cookie.java: Cookie provides support for converting between JSON and cookies.
CookieList.java: CookieList provides support for converting between JSON and
cookie lists.
HTTP.java: HTTP provides support for converting between JSON and HTTP headers.
HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers.
XML.java: XML provides support for converting between JSON and XML.
JSONML.java: JSONML provides support for converting between JSONML and XML.
XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text.
Unit tests are maintained in a separate project. Contributing developers can test
JSON-java pull requests with the code in this project:
https://github.com/stleary/JSON-Java-unit-test
Numeric types in this package comply with ECMA-404: The JSON Data Interchange Format
(http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) and
RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
(https://tools.ietf.org/html/rfc7159#section-6).
This package fully supports Integer, Long, and Double Java types. Partial support
for BigInteger and BigDecimal values in JSONObject and JSONArray objects is provided
in the form of get(), opt(), and put() API methods.
Although 1.6 compatibility is currently supported, it is not a project goal and may be
removed in some future release.
In compliance with RFC7159 page 10 section 9, the parser is more lax with what is valid
JSON than the Generator. For Example, the tab character (U+0009) is allowed when reading
JSON Text strings, but when output by the Generator, tab is properly converted to \t in
the string. Other instances may occur where reading invalid JSON text does not cause an
error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or
invalid number formats (1.2e6.3) will cause errors as such documents can not be read
reliably.
Release history:
20160807 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
20160212 Java 1.6 compatibility, OSGi bundle. Contains the latest code as of 12 Feb, 2016.
20151123 JSONObject and JSONArray initialization with generics. Contains the
latest code as of 23 Nov, 2015.
20150729 Checkpoint for Maven central repository release. Contains the latest code
as of 29 July, 2015.
JSON-java releases can be found by searching the Maven repository for groupId "org.json"
and artifactId "json". For example:
https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.json%22%20AND%20a%3A%22json%22

138
README.md Normal file
View File

@@ -0,0 +1,138 @@
JSON in Java [package org.json]
===============================
[![Maven Central](https://img.shields.io/maven-central/v/org.json/json.svg)](https://mvnrepository.com/artifact/org.json/json)
**[Click here if you just want the latest release jar file.](http://central.maven.org/maven2/org/json/json/20180813/json-20180813.jar)**
JSON is a light-weight, language independent, data interchange format.
See http://www.JSON.org/
The files in this package implement JSON encoders/decoders in Java.
It also includes the capability to convert between JSON and XML, HTTP
headers, Cookies, and CDL.
This is a reference implementation. There is a large number of JSON packages
in Java. Perhaps someday the Java community will standardize on one. Until
then, choose carefully.
The license includes this restriction: "The software shall be used for good,
not evil." If your conscience cannot live with that, then choose a different
package.
The package compiles on Java 1.6-1.8.
**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 `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.
**JSONTokener.java**: The `JSONTokener` breaks a text into a sequence of individual
tokens. It can be constructed from a `String`, `Reader`, or `InputStream`.
**JSONException.java**: The `JSONException` is the standard exception type thrown
by this package.
**JSONPointer.java**: Implementation of
[JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901). Supports
JSON Pointers both in the form of string representation and URI fragment
representation.
**JSONPropertyIgnore.java**: Annotation class that can be used on Java Bean getter methods.
When used on a bean method that would normally be serialized into a `JSONObject`, it
overrides the getter-to-key-name logic and forces the property to be excluded from the
resulting `JSONObject`.
**JSONPropertyName.java**: Annotation class that can be used on Java Bean getter methods.
When used on a bean method that would normally be serialized into a `JSONObject`, it
overrides the getter-to-key-name logic and uses the value of the annotation. The Bean
processor will look through the class hierarchy. This means you can use the annotation on
a base class or interface and the value of the annotation will be used even if the getter
is overridden in a child class.
**JSONString.java**: The `JSONString` interface requires a `toJSONString` method,
allowing an object to provide its own serialization.
**JSONStringer.java**: The `JSONStringer` provides a convenient facility for
building JSON strings.
**JSONWriter.java**: The `JSONWriter` provides a convenient facility for building
JSON text through a writer.
**CDL.java**: `CDL` provides support for converting between JSON and comma
delimited lists.
**Cookie.java**: `Cookie` provides support for converting between JSON and cookies.
**CookieList.java**: `CookieList` provides support for converting between JSON and
cookie lists.
**HTTP.java**: `HTTP` provides support for converting between JSON and HTTP headers.
**HTTPTokener.java**: `HTTPTokener` extends `JSONTokener` for parsing HTTP headers.
**XML.java**: `XML` provides support for converting between JSON and XML.
**JSONML.java**: `JSONML` provides support for converting between JSONML and XML.
**XMLTokener.java**: `XMLTokener` extends `JSONTokener` for parsing XML text.
Unit tests are maintained in a separate project. Contributing developers can test
JSON-java pull requests with the code in this project:
https://github.com/stleary/JSON-Java-unit-test
Numeric types in this package comply with
[ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf) and
[RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc8259#section-6).
This package fully supports `Integer`, `Long`, and `Double` Java types. Partial support
for `BigInteger` and `BigDecimal` values in `JSONObject` and `JSONArray` objects is provided
in the form of `get()`, `opt()`, and `put()` API methods.
Although 1.6 compatibility is currently supported, it is not a project goal and may be
removed in some future release.
In compliance with RFC8259 page 10 section 9, the parser is more lax with what is valid
JSON than the Generator. For Example, the tab character (U+0009) is allowed when reading
JSON Text strings, but when output by the Generator, tab is properly converted to \t in
the string. Other instances may occur where reading invalid JSON text does not cause an
error to be generated. Malformed JSON Texts such as missing end " (quote) on strings or
invalid number formats (1.2e6.3) will cause errors as such documents can not be read
reliably.
Release history:
~~~
20180813 POM change to include Automatic-Module-Name (#431)
20180130 Recent commits
20171018 Checkpoint for recent commits.
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
20160212 Java 1.6 compatibility, OSGi bundle. Contains the latest code as of 12 Feb, 2016.
20151123 JSONObject and JSONArray initialization with generics. Contains the
latest code as of 23 Nov, 2015.
20150729 Checkpoint for Maven central repository release. Contains the latest code
as of 29 July, 2015.
~~~
JSON-java releases can be found by searching the Maven repository for groupId "org.json"
and artifactId "json". For example:
https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav

375
XML.java
View File

@@ -24,6 +24,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import java.io.Reader;
import java.io.StringReader;
import java.util.Iterator;
/**
@@ -31,7 +33,7 @@ import java.util.Iterator;
* covert a JSONObject into an XML text.
*
* @author JSON.org
* @version 2016-01-30
* @version 2016-08-10
*/
@SuppressWarnings("boxing")
public class XML {
@@ -63,6 +65,51 @@ public class XML {
/** The Character '/'. */
public static final Character SLASH = '/';
/**
* Null attrubute name
*/
public static final String NULL_ATTR = "xsi:nil";
/**
* 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 +118,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 +127,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 +145,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);
}
}
@@ -137,7 +247,7 @@ public class XML {
* @return true if the close tag is processed.
* @throws JSONException
*/
private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings)
private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config)
throws JSONException {
char c;
int i;
@@ -174,7 +284,7 @@ public class XML {
if (x.next() == '[') {
string = x.nextCDATA();
if (string.length() > 0) {
context.accumulate("content", string);
context.accumulate(config.cDataTagName, string);
}
return false;
}
@@ -223,11 +333,11 @@ public class XML {
tagName = (String) token;
token = null;
jsonobject = new JSONObject();
boolean nilAttributeFound = false;
for (;;) {
if (token == null) {
token = x.nextToken();
}
// attribute = value
if (token instanceof String) {
string = (String) token;
@@ -237,8 +347,17 @@ public class XML {
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
if (config.convertNilAttributeToNull
&& NULL_ATTR.equals(string)
&& Boolean.parseBoolean((String) token)) {
nilAttributeFound = true;
} else if (!nilAttributeFound) {
jsonobject.accumulate(string,
keepStrings ? token : JSONObject.stringToValue((String) token));
config.keepStrings
? ((String) token)
: stringToValue((String) token));
}
token = null;
} else {
jsonobject.accumulate(string, "");
@@ -250,7 +369,9 @@ public class XML {
if (x.nextToken() != GT) {
throw x.syntaxError("Misshaped tag");
}
if (jsonobject.length() > 0) {
if (nilAttributeFound) {
context.accumulate(tagName, JSONObject.NULL);
} else if (jsonobject.length() > 0) {
context.accumulate(tagName, jsonobject);
} else {
context.accumulate(tagName, "");
@@ -269,19 +390,19 @@ public class XML {
} else if (token instanceof String) {
string = (String) token;
if (string.length() > 0) {
jsonobject.accumulate("content",
keepStrings ? token : JSONObject.stringToValue(string));
jsonobject.accumulate(config.cDataTagName,
config.keepStrings ? string : stringToValue(string));
}
} else if (token == LT) {
// Nested element
if (parse(x, jsonobject, tagName,keepStrings)) {
if (parse(x, jsonobject, tagName, config)) {
if (jsonobject.length() == 0) {
context.accumulate(tagName, "");
} else if (jsonobject.length() == 1
&& jsonobject.opt("content") != null) {
&& jsonobject.opt(config.cDataTagName) != null) {
context.accumulate(tagName,
jsonobject.opt("content"));
jsonobject.opt(config.cDataTagName));
} else {
context.accumulate(tagName, jsonobject);
}
@@ -297,16 +418,56 @@ 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)}.
*
* @deprecated Use {@link JSONObject#stringToValue(String)} instead.
* @param string String to convert
* @return JSON value of this string or the string
*/
@Deprecated
// To maintain compatibility with the Android API, this method is a direct copy of
// the one in JSONObject. Changes made here should be reflected there.
public static Object stringToValue(String string) {
return JSONObject.stringToValue(string);
if (string.equals("")) {
return string;
}
if (string.equalsIgnoreCase("true")) {
return Boolean.TRUE;
}
if (string.equalsIgnoreCase("false")) {
return Boolean.FALSE;
}
if (string.equalsIgnoreCase("null")) {
return JSONObject.NULL;
}
/*
* If it might be a number, try converting it. If a number cannot be
* produced, then the value will just be a string.
*/
char initial = string.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
try {
// if we want full Big Number support this block can be replaced with:
// return stringToNumber(string);
if (string.indexOf('.') > -1 || string.indexOf('e') > -1
|| string.indexOf('E') > -1 || "-0".equals(string)) {
Double d = Double.valueOf(string);
if (!d.isInfinite() && !d.isNaN()) {
return d;
}
} else {
Long myLong = Long.valueOf(string);
if (string.equals(myLong.toString())) {
if (myLong.longValue() == myLong.intValue()) {
return Integer.valueOf(myLong.intValue());
}
return myLong;
}
}
} catch (Exception ignore) {
}
}
return string;
}
/**
@@ -326,9 +487,85 @@ public class XML {
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string) throws JSONException {
return toJSONObject(string, false);
return toJSONObject(string, XMLParserConfiguration.ORIGINAL);
}
/**
* Convert a well-formed (but not necessarily valid) XML into a
* JSONObject. Some information may be lost in this transformation because
* JSON is a data format and XML is a document format. XML uses elements,
* attributes, and content text, while JSON uses unordered collections of
* name/value pairs and arrays of values. JSON does not does not like to
* distinguish between elements and attributes. Sequences of similar
* elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored.
*
* @param reader The XML source reader.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(Reader reader) throws JSONException {
return toJSONObject(reader, XMLParserConfiguration.ORIGINAL);
}
/**
* Convert a well-formed (but not necessarily valid) XML into a
* JSONObject. Some information may be lost in this transformation because
* JSON is a data format and XML is a document format. XML uses elements,
* attributes, and content text, while JSON uses unordered collections of
* name/value pairs and arrays of values. JSON does not does not like to
* distinguish between elements and attributes. Sequences of similar
* elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored.
*
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
* numbers but will instead be the exact value as seen in the XML document.
*
* @param reader The XML source reader.
* @param keepStrings If true, then values will not be coerced into boolean
* or numeric values and will instead be left as strings
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException {
if(keepStrings) {
return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS);
}
return toJSONObject(reader, XMLParserConfiguration.ORIGINAL);
}
/**
* Convert a well-formed (but not necessarily valid) XML into a
* JSONObject. Some information may be lost in this transformation because
* JSON is a data format and XML is a document format. XML uses elements,
* attributes, and content text, while JSON uses unordered collections of
* name/value pairs and arrays of values. JSON does not does not like to
* distinguish between elements and attributes. Sequences of similar
* elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored.
*
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
* numbers but will instead be the exact value as seen in the XML document.
*
* @param reader The XML source reader.
* @param config Configuration options for the parser
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration config) throws JSONException {
JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(reader);
while (x.more()) {
x.skipPast("<");
if(x.more()) {
parse(x, jo, null, config);
}
}
return jo;
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
@@ -352,13 +589,33 @@ public class XML {
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
JSONObject jo = new JSONObject();
XMLTokener x = new XMLTokener(string);
while (x.more() && x.skipPast("<")) {
parse(x, jo, null, keepStrings);
return toJSONObject(new StringReader(string), keepStrings);
}
return jo;
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject. Some information may be lost in this transformation because
* JSON is a data format and XML is a document format. XML uses elements,
* attributes, and content text, while JSON uses unordered collections of
* name/value pairs and arrays of values. JSON does not does not like to
* distinguish between elements and attributes. Sequences of similar
* elements are represented as JSONArrays. Content text may be placed in a
* "content" member. Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code>
* are ignored.
*
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
* numbers but will instead be the exact value as seen in the XML document.
*
* @param string
* The source string.
* @param config Configuration options for the parser.
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(String string, XMLParserConfiguration config) throws JSONException {
return toJSONObject(new StringReader(string), config);
}
/**
* Convert a JSONObject into a well-formed, element-normal XML string.
*
@@ -368,7 +625,7 @@ public class XML {
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toString(Object object) throws JSONException {
return toString(object, null);
return toString(object, null, XMLParserConfiguration.ORIGINAL);
}
/**
@@ -381,15 +638,28 @@ 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) {
return toString(object, tagName, XMLParserConfiguration.ORIGINAL);
}
/**
* Convert a JSONObject into a well-formed, element-normal XML string.
*
* @param object
* A JSONObject.
* @param tagName
* The optional name of the enclosing tag.
* @param config
* Configuration that can control output to XML.
* @return A string.
* @throws JSONException Thrown if there is an error parsing the string
*/
public static String toString(final Object object, final String tagName, final XMLParserConfiguration config)
throws JSONException {
StringBuilder sb = new StringBuilder();
JSONArray ja;
JSONObject jo;
String key;
Iterator<String> keys;
String string;
Object value;
if (object instanceof JSONObject) {
@@ -401,29 +671,28 @@ public class XML {
}
// Loop thru the keys.
// don't use the new entrySet accessor to maintain Android Support
jo = (JSONObject) object;
keys = jo.keys();
while (keys.hasNext()) {
key = keys.next();
value = jo.opt(key);
for (final String key : jo.keySet()) {
Object value = jo.opt(key);
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)) {
if (key.equals(config.cDataTagName)) {
if (value instanceof JSONArray) {
ja = (JSONArray) value;
int i = 0;
for (Object val : ja) {
int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) {
if (i > 0) {
sb.append('\n');
}
Object val = ja.opt(i);
sb.append(escape(val.toString()));
i++;
}
} else {
sb.append(escape(value.toString()));
@@ -433,17 +702,20 @@ public class XML {
} else if (value instanceof JSONArray) {
ja = (JSONArray) value;
for (Object val : ja) {
int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) {
Object val = ja.opt(i);
if (val instanceof JSONArray) {
sb.append('<');
sb.append(key);
sb.append('>');
sb.append(toString(val));
sb.append(toString(val, null, config));
sb.append("</");
sb.append(key);
sb.append('>');
} else {
sb.append(toString(val, key));
sb.append(toString(val, key, config));
}
}
} else if ("".equals(value)) {
@@ -454,7 +726,7 @@ public class XML {
// Emit a new tag <k>
} else {
sb.append(toString(value, key));
sb.append(toString(value, key, config));
}
}
if (tagName != null) {
@@ -468,22 +740,23 @@ public class XML {
}
if (object != null) {
if (object != null && (object instanceof JSONArray || object.getClass().isArray())) {
if(object.getClass().isArray()) {
object = new JSONArray(object);
}
if (object instanceof JSONArray) {
ja = new JSONArray(object);
} else {
ja = (JSONArray) object;
for (Object val : ja) {
}
int jaLength = ja.length();
// don't use the new iterator API to maintain support for Android
for (int i = 0; i < jaLength; i++) {
Object val = ja.opt(i);
// 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));
sb.append(toString(val, tagName == null ? "array" : tagName, config));
}
return sb.toString();
}
}
string = (object == null) ? "null" : escape(object.toString());
return (tagName == null) ? "\"" + string + "\""

107
XMLParserConfiguration.java Normal file
View File

@@ -0,0 +1,107 @@
package org.json;
/*
Copyright (c) 2002 JSON.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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.
*/
/**
* Configuration object for the XML parser.
* @author AylwardJ
*
*/
public class XMLParserConfiguration {
/** Original Configuration of the XML Parser. */
public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration();
/** Original configuration of the XML Parser except that values are kept as strings. */
public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration(true);
/**
* When parsing the XML into JSON, specifies if values should be kept as strings (true), or if
* they should try to be guessed into JSON values (numeric, boolean, string)
*/
public final boolean keepStrings;
/**
* The name of the key in a JSON Object that indicates a CDATA section. Historically this has
* been the value "content" but can be changed. Use <code>null</code> to indicate no CDATA
* processing.
*/
public final String cDataTagName;
/**
* When parsing the XML into JSON, specifies if values with attribute xsi:nil="true"
* should be kept as attribute(false), or they should be converted to null(true)
*/
public final boolean convertNilAttributeToNull;
/**
* Default parser configuration. Does not keep strings, and the CDATA Tag Name is "content".
*/
public XMLParserConfiguration () {
this(false, "content", false);
}
/**
* Configure the parser string processing and use the default CDATA Tag Name as "content".
* @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value.
*/
public XMLParserConfiguration (final boolean keepStrings) {
this(keepStrings, "content", false);
}
/**
* Configure the parser string processing to try and convert XML values to JSON values and
* use the passed CDATA Tag Name the processing value. Pass <code>null</code> to
* disable CDATA processing
* @param cDataTagName<code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA.
*/
public XMLParserConfiguration (final String cDataTagName) {
this(false, cDataTagName, false);
}
/**
* Configure the parser to use custom settings.
* @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value.
* @param cDataTagName<code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA.
*/
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) {
this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = false;
}
/**
* Configure the parser to use custom settings.
* @param keepStrings <code>true</code> to parse all values as string.
* <code>false</code> to try and convert XML string values into a JSON value.
* @param cDataTagName <code>null</code> to disable CDATA processing. Any other value
* to use that value as the JSONObject key name to process as CDATA.
* @param convertNilAttributeToNull <code>true</code> to parse values with attribute xsi:nil="true" as null.
* <code>false</code> to parse values with attribute xsi:nil="true" as {"xsi:nil":true}.
*/
public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) {
this.keepStrings = keepStrings;
this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = convertNilAttributeToNull;
}
}

View File

@@ -24,6 +24,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import java.io.Reader;
/**
* The XMLTokener extends the JSONTokener to provide additional methods
* for the parsing of XML texts.
@@ -47,6 +49,14 @@ public class XMLTokener extends JSONTokener {
entity.put("quot", XML.QUOT);
}
/**
* Construct an XMLTokener from a Reader.
* @param r A source reader.
*/
public XMLTokener(Reader r) {
super(r);
}
/**
* Construct an XMLTokener from a string.
* @param s A source string.
@@ -64,11 +74,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 +84,7 @@ public class XMLTokener extends JSONTokener {
return sb.toString();
}
}
throw syntaxError("Unclosed CDATA");
}
@@ -103,7 +111,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();
}
@@ -124,7 +135,7 @@ public class XMLTokener extends JSONTokener {
* @return A Character or an entity String if the entity is not recognized.
* @throws JSONException If missing ';' in XML entity.
*/
public Object nextEntity(char ampersand) throws JSONException {
public Object nextEntity(@SuppressWarnings("unused") char ampersand) throws JSONException {
StringBuilder sb = new StringBuilder();
for (;;) {
char c = next();
@@ -137,8 +148,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();
}
@@ -296,9 +336,11 @@ public class XMLTokener extends JSONTokener {
* Skip characters until past the requested string.
* If it is not found, we are left at the end of the source with a result of false.
* @param to A string to skip past.
* @throws JSONException
*/
public boolean skipPast(String to) throws JSONException {
// The Android implementation of JSONTokener has a public method of public void skipPast(String to)
// even though ours does not have that method, to have API compatibility, our method in the subclass
// should match.
public void skipPast(String to) {
boolean b;
char c;
int i;
@@ -315,7 +357,7 @@ public class XMLTokener extends JSONTokener {
for (i = 0; i < length; i += 1) {
c = next();
if (c == 0) {
return false;
return;
}
circle[i] = c;
}
@@ -342,14 +384,14 @@ public class XMLTokener extends JSONTokener {
/* If we exit the loop with b intact, then victory is ours. */
if (b) {
return true;
return;
}
/* Get the next character. If there isn't one, then defeat is ours. */
c = next();
if (c == 0) {
return false;
return;
}
/*
* Shove the character in the circle buffer and advance the