From 1272d80a034976d4c571fa62ae9c7efbc5a6814d Mon Sep 17 00:00:00 2001 From: Douglas Crockford Date: Tue, 20 May 2014 14:39:51 -0700 Subject: [PATCH 01/59] education --- zip/Huff.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/zip/Huff.java b/zip/Huff.java index 98c650e69..a7849ae93 100644 --- a/zip/Huff.java +++ b/zip/Huff.java @@ -29,7 +29,7 @@ of this software and associated documentation files (the "Software"), to deal /** * JSONzip is a compression scheme for JSON text. * @author JSON.org - * @version 2014-05-03 + * @version 2014-05-20 */ /** @@ -53,6 +53,11 @@ public class Huff implements None, PostMortem { */ private final int domain; + /** + * The number of characters to process before generation is no longer done. + */ + public static final int education = 1000000; + /** * An array that maps symbol values to symbols. */ @@ -140,7 +145,7 @@ public boolean postMortem(PostMortem pm) { */ public Huff(int domain) { this.domain = domain; - this.toLearn = 1000000; + this.toLearn = education; int length = domain * 2 - 1; this.symbols = new Symbol[length]; From aab1017e66f9faf03f5c49e9f167d2be66488215 Mon Sep 17 00:00:00 2001 From: Douglas Crockford Date: Tue, 20 May 2014 15:22:05 -0700 Subject: [PATCH 02/59] this.namehuffext.generate --- zip/JSONzip.java | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/zip/JSONzip.java b/zip/JSONzip.java index 220686de3..d8e3ac652 100644 --- a/zip/JSONzip.java +++ b/zip/JSONzip.java @@ -44,7 +44,7 @@ of this software and associated documentation files (the "Software"), to deal * ADEQUATELY FOR PRODUCTION USE. * * @author JSON.org - * @version 2014-05-03 + * @version 2014-05-20 */ public abstract class JSONzip implements None, PostMortem { /** @@ -55,29 +55,29 @@ public abstract class JSONzip implements None, PostMortem { }; /** - * The first positive integer than cannot be encoded in 4 bits. + * The end of string code. */ - public static final long int4 = 16; + public static final int end = 256; /** - * The first positive integer than cannot be encoded in 7 bits. + * The end of number code. */ - public static final long int7 = 144; + public static final int endOfNumber = bcd.length; /** - * The first positive integer than cannot be encoded in 14 bits. + * The first positive integer that cannot be encoded in 4 bits. */ - public static final long int14 = 16528; + public static final long int4 = 16; /** - * The end of string code. + * The first positive integer that cannot be encoded in 7 bits. */ - public static final int end = 256; + public static final long int7 = 144; /** - * The end of number code. + * The first positive integer that cannot be encoded in 14 bits. */ - public static final int endOfNumber = bcd.length; + public static final long int14 = 16528; /** * The package supports tracing for debugging. @@ -177,6 +177,7 @@ protected JSONzip() { */ protected void generate() { this.namehuff.generate(); + this.namehuffext.generate(); this.stringhuff.generate(); this.stringhuffext.generate(); } From 8114b976ce7224ff3b89f3d7e53f4207b7dcdf4f Mon Sep 17 00:00:00 2001 From: Douglas Crockford Date: Wed, 21 May 2014 20:59:05 -0700 Subject: [PATCH 03/59] deleted --- zip/MapKeep.java | 160 ------------------- zip/TrieKeep.java | 396 ---------------------------------------------- 2 files changed, 556 deletions(-) delete mode 100644 zip/MapKeep.java delete mode 100644 zip/TrieKeep.java diff --git a/zip/MapKeep.java b/zip/MapKeep.java deleted file mode 100644 index 1374e08d3..000000000 --- a/zip/MapKeep.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.json.zip; - -import java.util.HashMap; - -import org.json.Kim; - -/* - Copyright (c) 2013 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. - */ - -/** - * A keep is an associative data structure that maintains usage counts of each - * of the associations in its keeping. When the keep becomes full, it purges - * little used associations, and ages the survivors. Each key is assigned an - * integer value. When the keep is compacted, each key can be given a new - * value. - */ -class MapKeep extends Keep { - private Object[] list; - private HashMap map; - - /** - * Create a new Keep. - * @param bits - * The capacity of the keep expressed in the number of bits - * required to hold an integer. - */ - public MapKeep(int bits) { - super(bits); - this.list = new Object[this.capacity]; - this.map = new HashMap(this.capacity); - } - - /** - * Compact the keep. A keep may contain at most this.capacity elements. - * The keep contents can be reduced by deleting all elements with low use - * counts, and by reducing the use counts of the survivors. - */ - private void compact() { - int from = 0; - int to = 0; - while (from < this.capacity) { - Object key = this.list[from]; - long usage = age(this.uses[from]); - if (usage > 0) { - this.uses[to] = usage; - this.list[to] = key; - this.map.put(key, new Integer(to)); - to += 1; - } else { - this.map.remove(key); - } - from += 1; - } - if (to < this.capacity) { - this.length = to; - } else { - this.map.clear(); - this.length = 0; - } - this.power = 0; - } - - /** - * Find the integer value associated with this key, or nothing if this key - * is not in the keep. - * - * @param key - * An object. - * @return An integer - */ - public int find(Object key) { - Object o = this.map.get(key); - return o instanceof Integer ? ((Integer) o).intValue() : none; - } - - public boolean postMortem(PostMortem pm) { - MapKeep that = (MapKeep) pm; - if (this.length != that.length) { - JSONzip.log(this.length + " <> " + that.length); - return false; - } - for (int i = 0; i < this.length; i += 1) { - boolean b; - if (this.list[i] instanceof Kim) { - b = ((Kim) this.list[i]).equals(that.list[i]); - } else { - Object o = this.list[i]; - Object q = that.list[i]; - if (o instanceof Number) { - o = o.toString(); - } - if (q instanceof Number) { - q = q.toString(); - } - b = o.equals(q); - } - if (!b) { - JSONzip.log("\n[" + i + "]\n " + this.list[i] + "\n " - + that.list[i] + "\n " + this.uses[i] + "\n " - + that.uses[i]); - return false; - } - } - return true; - } - - /** - * Register a value in the keep. Compact the keep if it is full. The next - * time this value is encountered, its integer can be sent instead. - * @param value A value. - */ - public void register(Object value) { - if (JSONzip.probe) { - int integer = find(value); - if (integer >= 0) { - JSONzip.log("\nDuplicate key " + value); - } - } - if (this.length >= this.capacity) { - compact(); - } - this.list[this.length] = value; - this.map.put(value, new Integer(this.length)); - this.uses[this.length] = 1; - if (JSONzip.probe) { - JSONzip.log("<" + this.length + " " + value + "> "); - } - this.length += 1; - } - - /** - * Return the value associated with the integer. - * @param integer The number of an item in the keep. - * @return The value. - */ - public Object value(int integer) { - return this.list[integer]; - } -} diff --git a/zip/TrieKeep.java b/zip/TrieKeep.java deleted file mode 100644 index dcb13c7a0..000000000 --- a/zip/TrieKeep.java +++ /dev/null @@ -1,396 +0,0 @@ -package org.json.zip; - -import org.json.Kim; - -/* - Copyright (c) 2013 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. - */ - -/** - * A TrieKeep is a Keep that implements a Trie. - */ -class TrieKeep extends Keep { - - /** - * The trie is made of nodes. - */ - class Node implements PostMortem { - private int integer; - private Node[] next; - - /** - * Each non-leaf node contains links to up to 256 next nodes. Each node - * has an integer value. - */ - public Node() { - this.integer = none; - this.next = null; - } - - /** - * Get one of a node's 256 links. If it is a leaf node, it returns - * null. - * - * @param cell - * A integer between 0 and 255. - * @return - */ - public Node get(int cell) { - return this.next == null ? null : this.next[cell]; - } - - /** - * Get one of a node's 256 links. If it is a leap node, it returns - * null. The argument is treated as an unsigned integer. - * - * @param cell - * A byte. - * @return - */ - public Node get(byte cell) { - return get(((int) cell) & 0xFF); - } - - /** - * Compare two nodes. Their lengths must be equal. Their links must - * also compare. - */ - public boolean postMortem(PostMortem pm) { - Node that = (Node) pm; - if (that == null) { - JSONzip.log("\nMisalign"); - return false; - } - if (this.integer != that.integer) { - JSONzip.log("\nInteger " + this.integer + " <> " + - that.integer); - return false; - } - if (this.next == null) { - if (that.next == null) { - return true; - } - JSONzip.log("\nNext is null " + this.integer); - return false; - } - for (int i = 0; i < 256; i += 1) { - Node node = this.next[i]; - if (node != null) { - if (!node.postMortem(that.next[i])) { - return false; - } - } else if (that.next[i] != null) { - JSONzip.log("\nMisalign " + i); - return false; - } - } - return true; - } - - /** - * Set a node's link to another node. - * - * @param cell - * An integer between 0 and 255. - * @param node - * The new value for the cell. - */ - public void set(int cell, Node node) { - if (this.next == null) { - this.next = new Node[256]; - } - if (JSONzip.probe) { - if (node == null || this.next[cell] != null) { - JSONzip.log("\nUnexpected set.\n"); - } - } - this.next[cell] = node; - } - - /** - * Set a node's link to another node. - * - * @param cell - * A byte. - * @param node - * The new value for the cell. - */ - public void set(byte cell, Node node) { - set(((int) cell) & 0xFF, node); - } - - /** - * Get one of a node's 256 links. It will not return null. If there is - * no link, then a link is manufactured. - * - * @param cell - * A integer between 0 and 255. - * @return - */ - public Node vet(int cell) { - Node node = get(cell); - if (node == null) { - node = new Node(); - set(cell, node); - } - return node; - } - - /** - * Get one of a node's 256 links. It will not return null. If there is - * no link, then a link is manufactured. - * - * @param cell - * A byte. - * @return - */ - public Node vet(byte cell) { - return vet(((int) cell) & 0xFF); - } - } - - private int[] froms; - private int[] thrus; - private Node root; - private Kim[] kims; - - /** - * Create a new Keep of kims. - * - * @param bits - * The log2 of the capacity of the Keep. For example, if bits is - * 12, then the keep's capacity will be 4096. - */ - public TrieKeep(int bits) { - super(bits); - this.froms = new int[this.capacity]; - this.thrus = new int[this.capacity]; - this.kims = new Kim[this.capacity]; - this.root = new Node(); - } - - /** - * Get the kim associated with an integer. - * - * @param integer - * @return - */ - public Kim kim(int integer) { - Kim kim = this.kims[integer]; - int from = this.froms[integer]; - int thru = this.thrus[integer]; - if (from != 0 || thru != kim.length) { - kim = new Kim(kim, from, thru); - this.froms[integer] = 0; - this.thrus[integer] = kim.length; - this.kims[integer] = kim; - } - return kim; - } - - /** - * Get the length of the Kim associated with an integer. This is sometimes - * much faster than get(integer).length. - * - * @param integer - * @return - */ - public int length(int integer) { - return this.thrus[integer] - this.froms[integer]; - } - - /** - * Find the integer value associated with this key, or nothing if this key - * is not in the keep. - * - * @param key - * An object. - * @return An integer - */ - public int match(Kim kim, int from, int thru) { - Node node = this.root; - int best = none; - for (int at = from; at < thru; at += 1) { - node = node.get(kim.get(at)); - if (node == null) { - break; - } - if (node.integer != none) { - best = node.integer; - } - from += 1; - } - return best; - } - - public boolean postMortem(PostMortem pm) { - boolean result = true; - TrieKeep that = (TrieKeep) pm; - if (this.length != that.length) { - JSONzip.log("\nLength " + this.length + " <> " + that.length); - return false; - } - if (this.capacity != that.capacity) { - JSONzip.log("\nCapacity " + this.capacity + " <> " + - that.capacity); - return false; - } - for (int i = 0; i < this.length; i += 1) { - Kim thiskim = this.kim(i); - Kim thatkim = that.kim(i); - if (!thiskim.equals(thatkim)) { - JSONzip.log("\n[" + i + "] " + thiskim + " <> " + thatkim); - result = false; - } - } - return result && this.root.postMortem(that.root); - } - - public void registerMany(Kim kim) { - int length = kim.length; - int limit = this.capacity - this.length; - if (limit > JSONzip.substringLimit) { - limit = JSONzip.substringLimit; - } - int until = length - (JSONzip.minSubstringLength - 1); - for (int from = 0; from < until; from += 1) { - int len = length - from; - if (len > JSONzip.maxSubstringLength) { - len = JSONzip.maxSubstringLength; - } - len += from; - Node node = this.root; - for (int at = from; at < len; at += 1) { - Node next = node.vet(kim.get(at)); - if (next.integer == none - && at - from >= (JSONzip.minSubstringLength - 1)) { - next.integer = this.length; - this.uses[this.length] = 1; - this.kims[this.length] = kim; - this.froms[this.length] = from; - this.thrus[this.length] = at + 1; - if (JSONzip.probe) { - try { - JSONzip.log("<<" + this.length + " " - + new Kim(kim, from, at + 1) + ">> "); - } catch (Throwable ignore) { - } - } - this.length += 1; - limit -= 1; - if (limit <= 0) { - return; - } - } - node = next; - } - } - } - - public void registerOne(Kim kim) { - int integer = registerOne(kim, 0, kim.length); - if (integer != none) { - this.kims[integer] = kim; - } - } - - public int registerOne(Kim kim, int from, int thru) { - if (this.length < this.capacity) { - Node node = this.root; - for (int at = from; at < thru; at += 1) { - node = node.vet(kim.get(at)); - } - if (node.integer == none) { - int integer = this.length; - node.integer = integer; - this.uses[integer] = 1; - this.kims[integer] = kim; - this.froms[integer] = from; - this.thrus[integer] = thru; - if (JSONzip.probe) { - try { - JSONzip.log("<<" + integer + " " + new Kim(kim, from, thru) + ">> "); - } catch (Throwable ignore) { - } - } - this.length += 1; - return integer; - } - } - return none; - } - - /** - * Reserve space in the keep, compacting if necessary. A keep may contain - * at most -capacity- elements. The keep contents can be reduced by - * deleting all elements with low use counts, rebuilding the trie with the - * survivors. - */ - public void reserve() { - if (this.capacity - this.length < JSONzip.substringLimit) { - int from = 0; - int to = 0; - this.root = new Node(); - while (from < this.capacity) { - if (this.uses[from] > 1) { - Kim kim = this.kims[from]; - int thru = this.thrus[from]; - Node node = this.root; - for (int at = this.froms[from]; at < thru; at += 1) { - Node next = node.vet(kim.get(at)); - node = next; - } - node.integer = to; - this.uses[to] = age(this.uses[from]); - this.froms[to] = this.froms[from]; - this.thrus[to] = thru; - this.kims[to] = kim; - to += 1; - } - from += 1; - } - -// It is possible, but highly unlikely, that too many items survive. -// If that happens, clear the keep. - - if (this.capacity - to < JSONzip.substringLimit) { - this.power = 0; - this.root = new Node(); - to = 0; - } - this.length = to; - while (to < this.capacity) { - this.uses[to] = 0; - this.kims[to] = null; - this.froms[to] = 0; - this.thrus[to] = 0; - to += 1; - - } - } - } - - public Object value(int integer) { - return kim(integer); - } -} From 9b6872b6e52e28b1b99aa328c2109436de58622f Mon Sep 17 00:00:00 2001 From: Douglas Crockford Date: Fri, 6 Feb 2015 09:02:41 -0800 Subject: [PATCH 04/59] This package needs a new owner. --- Kim.java | 372 ------------------------------ README | 7 +- zip/BitInputStream.java | 153 ------------- zip/BitOutputStream.java | 154 ------------- zip/BitReader.java | 42 ---- zip/BitWriter.java | 45 ---- zip/Huff.java | 404 -------------------------------- zip/JSONzip.java | 255 --------------------- zip/Keep.java | 191 ---------------- zip/None.java | 15 -- zip/PostMortem.java | 47 ---- zip/README | 2 - zip/Unzipper.java | 310 ------------------------- zip/Zipper.java | 481 --------------------------------------- 14 files changed, 6 insertions(+), 2472 deletions(-) delete mode 100644 Kim.java delete mode 100644 zip/BitInputStream.java delete mode 100644 zip/BitOutputStream.java delete mode 100644 zip/BitReader.java delete mode 100644 zip/BitWriter.java delete mode 100644 zip/Huff.java delete mode 100644 zip/JSONzip.java delete mode 100644 zip/Keep.java delete mode 100644 zip/None.java delete mode 100644 zip/PostMortem.java delete mode 100644 zip/README delete mode 100644 zip/Unzipper.java delete mode 100644 zip/Zipper.java diff --git a/Kim.java b/Kim.java deleted file mode 100644 index 9f7af92d0..000000000 --- a/Kim.java +++ /dev/null @@ -1,372 +0,0 @@ -package org.json; - - -/* - Copyright (c) 2013 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. - */ - -/** - * Kim makes immutable eight bit Unicode strings. If the MSB of a byte is set, - * then the next byte is a continuation byte. The last byte of a character - * never has the MSB reset. Every byte that is not the last byte has the MSB - * set. Kim stands for "Keep it minimal". A Unicode character is never longer - * than 3 bytes. Every byte contributes 7 bits to the character. ASCII is - * unmodified. - * - * Kim UTF-8 - * one byte U+007F U+007F - * two bytes U+3FFF U+07FF - * three bytes U+10FFF U+FFFF - * four bytes U+10FFFF - * - * Characters in the ranges U+0800..U+3FFF and U+10000..U+10FFFF will be one - * byte smaller when encoded in Kim compared to UTF-8. - * - * Kim is beneficial when using scripts such as Old South Arabian, Aramaic, - * Avestan, Balinese, Batak, Bopomofo, Buginese, Buhid, Carian, Cherokee, - * Coptic, Cyrillic, Deseret, Egyptian Hieroglyphs, Ethiopic, Georgian, - * Glagolitic, Gothic, Hangul Jamo, Hanunoo, Hiragana, Kanbun, Kaithi, - * Kannada, Katakana, Kharoshthi, Khmer, Lao, Lepcha, Limbu, Lycian, Lydian, - * Malayalam, Mandaic, Meroitic, Miao, Mongolian, Myanmar, New Tai Lue, - * Ol Chiki, Old Turkic, Oriya, Osmanya, Pahlavi, Parthian, Phags-Pa, - * Phoenician, Samaritan, Sharada, Sinhala, Sora Sompeng, Tagalog, Tagbanwa, - * Takri, Tai Le, Tai Tham, Tamil, Telugu, Thai, Tibetan, Tifinagh, UCAS. - * - * A kim object can be constructed from an ordinary UTF-16 string, or from a - * byte array. A kim object can produce a UTF-16 string. - * - * As with UTF-8, it is possible to detect character boundaries within a byte - * sequence. UTF-8 is one of the world's great inventions. While Kim is more - * efficient, it is not clear that it is worth the expense of transition. - * - * @version 2013-04-18 - */ -public class Kim { - - /** - * The byte array containing the kim's content. - */ - private byte[] bytes = null; - - /** - * The kim's hashcode, conforming to Java's hashcode conventions. - */ - private int hashcode = 0; - - /** - * The number of bytes in the kim. The number of bytes can be as much as - * three times the number of characters. - */ - public int length = 0; - - /** - * The memoization of toString(). - */ - private String string = null; - - /** - * Make a kim from a portion of a byte array. - * - * @param bytes - * A byte array. - * @param from - * The index of the first byte. - * @param thru - * The index of the last byte plus one. - */ - public Kim(byte[] bytes, int from, int thru) { - -// As the bytes are copied into the new kim, a hashcode is computed using a -// modified Fletcher code. - - int sum = 1; - int value; - this.hashcode = 0; - this.length = thru - from; - if (this.length > 0) { - this.bytes = new byte[this.length]; - for (int at = 0; at < this.length; at += 1) { - value = (int) bytes[at + from] & 0xFF; - sum += value; - this.hashcode += sum; - this.bytes[at] = (byte) value; - } - this.hashcode += sum << 16; - } - } - - /** - * Make a kim from a byte array. - * - * @param bytes - * The byte array. - * @param length - * The number of bytes. - */ - public Kim(byte[] bytes, int length) { - this(bytes, 0, length); - } - - /** - * Make a new kim from a substring of an existing kim. The coordinates are - * in byte units, not character units. - * - * @param kim - * The source of bytes. - * @param from - * The point at which to take bytes. - * @param thru - * The point at which to stop taking bytes. - */ - public Kim(Kim kim, int from, int thru) { - this(kim.bytes, from, thru); - } - - /** - * Make a kim from a string. - * - * @param string - * The string. - * @throws JSONException - * if surrogate pair mismatch. - */ - public Kim(String string) throws JSONException { - int stringLength = string.length(); - this.hashcode = 0; - this.length = 0; - -// First pass: Determine the length of the kim, allowing for the UTF-16 -// to UTF-32 conversion, and then the UTF-32 to Kim conversion. - - if (stringLength > 0) { - for (int i = 0; i < stringLength; i += 1) { - int c = string.charAt(i); - if (c <= 0x7F) { - this.length += 1; - } else if (c <= 0x3FFF) { - this.length += 2; - } else { - if (c >= 0xD800 && c <= 0xDFFF) { - i += 1; - int d = string.charAt(i); - if (c > 0xDBFF || d < 0xDC00 || d > 0xDFFF) { - throw new JSONException("Bad UTF16"); - } - } - this.length += 3; - } - } - -// Second pass: Allocate a byte array and fill that array with the conversion -// while computing the hashcode. - - this.bytes = new byte[length]; - int at = 0; - int b; - int sum = 1; - for (int i = 0; i < stringLength; i += 1) { - int character = string.charAt(i); - if (character <= 0x7F) { - bytes[at] = (byte) character; - sum += character; - this.hashcode += sum; - at += 1; - } else if (character <= 0x3FFF) { - b = 0x80 | (character >>> 7); - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - b = character & 0x7F; - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - } else { - if (character >= 0xD800 && character <= 0xDBFF) { - i += 1; - character = (((character & 0x3FF) << 10) | (string - .charAt(i) & 0x3FF)) + 65536; - } - b = 0x80 | (character >>> 14); - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - b = 0x80 | ((character >>> 7) & 0xFF); - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - b = character & 0x7F; - bytes[at] = (byte) b; - sum += b; - this.hashcode += sum; - at += 1; - } - } - this.hashcode += sum << 16; - } - } - - /** - * Returns the character at the specified index. The index refers to byte - * values and ranges from 0 to length - 1. The index of the next character - * is at index + Kim.characterSize(kim.characterAt(index)). - * - * @param at - * the index of the char value. The first character is at 0. - * @returns a Unicode character between 0 and 0x10FFFF. - * @throws JSONException - * if at does not point to a valid character. - */ - public int characterAt(int at) throws JSONException { - int c = get(at); - if ((c & 0x80) == 0) { - return c; - } - int character; - int c1 = get(at + 1); - if ((c1 & 0x80) == 0) { - character = ((c & 0x7F) << 7) | c1; - if (character > 0x7F) { - return character; - } - } else { - int c2 = get(at + 2); - character = ((c & 0x7F) << 14) | ((c1 & 0x7F) << 7) | c2; - if ((c2 & 0x80) == 0 && character > 0x3FFF && character <= 0x10FFFF - && (character < 0xD800 || character > 0xDFFF)) { - return character; - } - } - throw new JSONException("Bad character at " + at); - } - - /** - * Returns the number of bytes needed to contain the character in Kim - * format. - * - * @param character - * a Unicode character between 0 and 0x10FFFF. - * @return 1, 2, or 3 - * @throws JSONException - * if the character is not representable in a kim. - */ - public static int characterSize(int character) throws JSONException { - if (character < 0 || character > 0x10FFFF) { - throw new JSONException("Bad character " + character); - } - return character <= 0x7F ? 1 : character <= 0x3FFF ? 2 : 3; - } - - /** - * Copy the contents of this kim to a byte array. - * - * @param bytes - * A byte array of sufficient size. - * @param at - * The position within the byte array to take the byes. - * @return The position immediately after the copy. - */ - public int copy(byte[] bytes, int at) { - System.arraycopy(this.bytes, 0, bytes, at, this.length); - return at + this.length; - } - - /** - * Two kim objects containing exactly the same bytes in the same order are - * equal to each other. - * - * @param obj - * the other kim with which to compare. - * @returns true if this and obj are both kim objects containing identical - * byte sequences. - */ - public boolean equals(Object obj) { - if (!(obj instanceof Kim)) { - return false; - } - Kim that = (Kim) obj; - if (this == that) { - return true; - } - if (this.hashcode != that.hashcode) { - return false; - } - return java.util.Arrays.equals(this.bytes, that.bytes); - } - - /** - * Get a byte from a kim. - * @param at - * The position of the byte. The first byte is at 0. - * @return The byte. - * @throws JSONException - * if there is no byte at that position. - */ - public int get(int at) throws JSONException { - if (at < 0 || at > this.length) { - throw new JSONException("Bad character at " + at); - } - return ((int) this.bytes[at]) & 0xFF; - } - - /** - * Returns a hash code value for the kim. - */ - public int hashCode() { - return this.hashcode; - } - - /** - * Produce a UTF-16 String from this kim. The number of codepoints in the - * string will not be greater than the number of bytes in the kim, although - * it could be less. - * - * @return The string. A kim memoizes its string representation. - * @throws JSONException - * if the kim is not valid. - */ - public String toString() throws JSONException { - if (this.string == null) { - int c; - int length = 0; - char chars[] = new char[this.length]; - for (int at = 0; at < this.length; at += characterSize(c)) { - c = this.characterAt(at); - if (c < 0x10000) { - chars[length] = (char) c; - length += 1; - } else { - chars[length] = (char) (0xD800 | ((c - 0x10000) >>> 10)); - length += 1; - chars[length] = (char) (0xDC00 | (c & 0x03FF)); - length += 1; - } - } - this.string = new String(chars, 0, length); - } - return this.string; - } -} diff --git a/README b/README index 6afe0c691..2de22ffc4 100755 --- a/README +++ b/README @@ -1,9 +1,14 @@ JSON in Java [package org.json] +This package needs a new owner. I have not used it in over a decade, and I do +not have time to maintain programs that I do not use. + +If you think you can give this package a good home, please contact me. + Douglas Crockford douglas@crockford.com -2011-02-02 +2015-02-06 JSON is a light-weight, language independent, data interchange format. diff --git a/zip/BitInputStream.java b/zip/BitInputStream.java deleted file mode 100644 index 2282d30c0..000000000 --- a/zip/BitInputStream.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.json.zip; - -import java.io.IOException; -import java.io.InputStream; - -/* - Copyright (c) 2013 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. - */ - -/** - * This is a big endian bit reader. It reads its bits from an InputStream. - * - * @version 2013-05-03 - * - */ -public class BitInputStream implements BitReader { - /** - * The number of bits remaining in the current byte. - */ - private int available = 0; - - /** - * Up to a byte's worth of unread bits. - */ - private int unread = 0; - - /** - * The source of the bits. - */ - private InputStream in; - - /** - * The number of bits read so far. This is used in padding. - */ - private long nrBits = 0; - - /** - * Make a BitReader from an InputStream. The BitReader will take bytes from - * the InputStream and unpack them into bits. - * - * @param in - * An InputStream. - */ - public BitInputStream(InputStream in) { - this.in = in; - } - - /** - * Read one bit. - * - * @return true if it is a 1 bit. - */ - public boolean bit() throws IOException { - return read(1) != 0; - } - - /** - * Get the number of bits that have been read from this BitInputStream. - * This includes pad bits that have been skipped, but might not include - * bytes that have been read from the underlying InputStream that have not - * yet been delivered as bits. - * - * @return The number of bits read so far. - */ - public long nrBits() { - return this.nrBits; - } - - /** - * Check that the rest of the block has been padded with zeroes. - * - * @param width - * The size of the block to pad in bits. - * This will typically be 8, 16, 32, 64, 128, 256, etc. - * @return true if the block was zero padded, or false if the the padding - * contains any one bits. - * @throws IOException - */ - public boolean pad(int width) throws IOException { - boolean result = true; - int gap = (int)this.nrBits % width; - if (gap < 0) { - gap += width; - } - if (gap != 0) { - int padding = width - gap; - while (padding > 0) { - if (bit()) { - result = false; - } - padding -= 1; - } - } - return result; - } - - /** - * Read some bits. - * - * @param width - * The number of bits to read. (0..32) - * @throws IOException - * @return the bits - */ - public int read(int width) throws IOException { - if (width == 0) { - return 0; - } - if (width < 0 || width > 32) { - throw new IOException("Bad read width."); - } - int result = 0; - while (width > 0) { - if (this.available == 0) { - this.unread = this.in.read(); - if (this.unread < 0) { - throw new IOException("Attempt to read past end."); - } - this.available = 8; - } - int take = width; - if (take > this.available) { - take = this.available; - } - result |= ((this.unread >>> (this.available - take)) & - ((1 << take) - 1)) << (width - take); - this.nrBits += take; - this.available -= take; - width -= take; - } - return result; - } -} diff --git a/zip/BitOutputStream.java b/zip/BitOutputStream.java deleted file mode 100644 index da47301cf..000000000 --- a/zip/BitOutputStream.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.json.zip; - -import java.io.IOException; -import java.io.OutputStream; - -/* - Copyright (c) 2013 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. - */ - -/** - * This is a big endian bit writer. It writes its bits to an OutputStream. - * - * @version 2013-05-03 - * - */ -public class BitOutputStream implements BitWriter { - - /** - * The number of bits written. - */ - private long nrBits = 0; - - /** - * The destination of the bits. - */ - private OutputStream out; - - /** - * Holder of bits not yet written. - */ - private int unwritten; - - /** - * The number of unused bits in this.unwritten. - */ - private int vacant = 8; - - /** - * Use an OutputStream to produce a BitWriter. The BitWriter will send its - * bits to the OutputStream as each byte is filled. - * - * @param out - * An Output Stream - */ - public BitOutputStream(OutputStream out) { - this.out = out; - } - - /** - * Returns the number of bits that have been written to this - * bitOutputStream. This may include bits that have not yet been written - * to the underlying outputStream. - */ - public long nrBits() { - return this.nrBits; - } - - /** - * Write a 1 bit. - * - * @throws IOException - */ - public void one() throws IOException { - write(1, 1); - } - - /** - * Pad the rest of the block with zeros and flush. pad(8) flushes the last - * unfinished byte. The underlying OutputStream will be flushed. - * - * @param width - * The size of the block to pad in bits. - * This will typically be 8, 16, 32, 64, 128, 256, etc. - * @throws IOException - */ - public void pad(int width) throws IOException { - int gap = (int)this.nrBits % width; - if (gap < 0) { - gap += width; - } - if (gap != 0) { - int padding = width - gap; - while (padding > 0) { - this.zero(); - padding -= 1; - } - } - this.out.flush(); - } - - /** - * Write some bits. Up to 32 bits can be written at a time. - * - * @param bits - * The bits to be written. - * @param width - * The number of bits to write. (0..32) - * @throws IOException - */ - public void write(int bits, int width) throws IOException { - if (bits == 0 && width == 0) { - return; - } - if (width <= 0 || width > 32) { - throw new IOException("Bad write width."); - } - while (width > 0) { - int actual = width; - if (actual > this.vacant) { - actual = this.vacant; - } - this.unwritten |= ((bits >>> (width - actual)) & - ((1 << actual) - 1)) << (this.vacant - actual); - width -= actual; - nrBits += actual; - this.vacant -= actual; - if (this.vacant == 0) { - this.out.write(this.unwritten); - this.unwritten = 0; - this.vacant = 8; - } - } - } - - /** - * Write a 0 bit. - * - * @throws IOException - */ - public void zero() throws IOException { - write(0, 1); - - } -} diff --git a/zip/BitReader.java b/zip/BitReader.java deleted file mode 100644 index 4fd99dbbf..000000000 --- a/zip/BitReader.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.json.zip; - -import java.io.IOException; - -public interface BitReader { - - /** - * Read one bit. - * - * @return true if it is a 1 bit. - */ - public boolean bit() throws IOException; - - /** - * Returns the number of bits that have been read from this bitreader. - * - * @return The number of bits read so far. - */ - public long nrBits(); - - /** - * Check that the rest of the block has been padded with zeros. - * - * @param width - * The size in bits of the block to pad. This will typically be - * 8, 16, 32, 64, 128, 256, etc. - * @return true if the block was zero padded, or false if the the padding - * contained any one bits. - * @throws IOException - */ - public boolean pad(int width) throws IOException; - - /** - * Read some bits. - * - * @param width - * The number of bits to read. (0..32) - * @throws IOException - * @return the bits - */ - public int read(int width) throws IOException; -} diff --git a/zip/BitWriter.java b/zip/BitWriter.java deleted file mode 100644 index ba8a109c6..000000000 --- a/zip/BitWriter.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.json.zip; - -import java.io.IOException; - -/** - * A bitwriter is a an interface that allows for doing output at the bit level. - * Most IO interfaces only allow for writing at the byte level or higher. - */ -public interface BitWriter { - - /** - * Write a 1 bit. - * - * @throws IOException - */ - public void one() throws IOException; - - /** - * Pad the rest of the block with zeros and flush. - * - * @param width - * The size in bits of the block to pad. This will typically be - * 8, 16, 32, 64, 128, 256, etc. - * @throws IOException - */ - public void pad(int width) throws IOException; - - /** - * Write some bits. Up to 32 bits can be written at a time. - * - * @param bits - * The bits to be written. - * @param width - * The number of bits to write. (0..32) - * @throws IOException - */ - public void write(int bits, int width) throws IOException; - - /** - * Write a 0 bit. - * - * @throws IOException - */ - public void zero() throws IOException; -} diff --git a/zip/Huff.java b/zip/Huff.java deleted file mode 100644 index a7849ae93..000000000 --- a/zip/Huff.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.json.zip; - -import org.json.JSONException; - -/* - Copyright (c) 2013 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. - */ - -/** - * JSONzip is a compression scheme for JSON text. - * @author JSON.org - * @version 2014-05-20 - */ - -/** - * A Huffman encoder/decoder. It operates over a domain of integers, which may - * map to characters or other symbols. Symbols that are used frequently are - * given shorter codes than symbols that are used infrequently. This usually - * produces shorter messages. - * - * Initially, all of the symbols are given the same weight. The weight of a - * symbol is incremented by the tick method. The generate method is used to - * generate the encoding table. The table must be generated before encoding or - * decoding. You may regenerate the table with the latest weights at any time. - * - * After a million ticks, it is assumed that the distribution is well - * understood and that no more regeneration will be required. - */ -public class Huff implements None, PostMortem { - - /** - * The number of symbols known to the encoder. - */ - private final int domain; - - /** - * The number of characters to process before generation is no longer done. - */ - public static final int education = 1000000; - - /** - * An array that maps symbol values to symbols. - */ - private final Symbol[] symbols; - - /** - * The root of the decoding table, and the terminal of the encoding table. - */ - private Symbol table; - - /** - * The number of characters left to learn to adapt the coding table. - */ - private int toLearn; - - /** - * Have any weights changed since the table was last generated? - */ - private boolean upToDate = false; - - /** - * The number of bits in the last symbol. This is used in tracing. - */ - private int width; - - private static class Symbol implements PostMortem { - public Symbol back; - public Symbol next; - public Symbol zero; - public Symbol one; - public final int integer; - public long weight; - - /** - * Make a symbol representing a character or other value. - * - * @param integer - * The symbol's number - */ - public Symbol(int integer) { - this.integer = integer; - this.weight = 0; - this.next = null; - this.back = null; - this.one = null; - this.zero = null; - } - - public boolean postMortem(PostMortem pm) { - boolean result = true; - Symbol that = (Symbol) pm; - - if (this.integer != that.integer || this.weight != that.weight) { - return false; - } - if ((this.back == null) != (that.back == null)) { - return false; - } - Symbol zero = this.zero; - Symbol one = this.one; - if (zero == null) { - if (that.zero != null) { - return false; - } - } else { - result = zero.postMortem(that.zero); - } - if (one == null) { - if (that.one != null) { - return false; - } - } else { - result = one.postMortem(that.one); - } - return result; - } - - } - - /** - * Construct a Huffman encoder/decoder. - * - * @param domain - * The number of values known to the object. - */ - public Huff(int domain) { - this.domain = domain; - this.toLearn = education; - int length = domain * 2 - 1; - this.symbols = new Symbol[length]; - -// Make the leaf symbols. - - for (int i = 0; i < domain; i += 1) { - symbols[i] = new Symbol(i); - } - -// Make the links. - - for (int i = domain; i < length; i += 1) { - symbols[i] = new Symbol(none); - } - } - - /** - * Generate the encoding/decoding table. The table determines the bit - * sequences used by the read and write methods. - */ - public void generate() { - if (!this.upToDate) { - -// Phase One: Sort the symbols by weight into a linked list. - - Symbol head = this.symbols[0]; - Symbol next; - Symbol previous = head; - Symbol symbol; - - this.table = null; - head.next = null; - for (int i = 1; i < this.domain; i += 1) { - symbol = symbols[i]; - -// If this symbol weights less than the head, then it becomes the new head. - - if (symbol.weight < head.weight) { - symbol.next = head; - head = symbol; - } else { - -// We will start the search from the previous symbol instead of the head unless -// the current symbol weights less than the previous symbol. - - if (symbol.weight < previous.weight) { - previous = head; - } - -// Find a connected pair (previous and next) where the symbol weighs the same -// or more than previous but less than the next. Link the symbol between them. - - while (true) { - next = previous.next; - if (next == null || symbol.weight < next.weight) { - break; - } - previous = next; - } - symbol.next = next; - previous.next = symbol; - previous = symbol; - } - } - -// Phase Two: Make new symbols from the two lightest symbols until only one -// symbol remains. The final symbol becomes the root of the table binary tree. - - int avail = this.domain; - Symbol first; - Symbol second; - previous = head; - while (true) { - first = head; - second = first.next; - head = second.next; - symbol = this.symbols[avail]; - avail += 1; - symbol.weight = first.weight + second.weight; - symbol.zero = first; - symbol.one = second; - symbol.back = null; - first.back = symbol; - second.back = symbol; - if (head == null) { - break; - } - -// Insert the new symbol back into the sorted list. - - if (symbol.weight < head.weight) { - symbol.next = head; - head = symbol; - previous = head; - } else { - while (true) { - next = previous.next; - if (next == null || symbol.weight < next.weight) { - break; - } - previous = next; - } - symbol.next = next; - previous.next = symbol; - previous = symbol; - } - - } - -// The last remaining symbol is the root of the table. - - this.table = symbol; - this.upToDate = true; - } - } - - private boolean postMortem(int integer) { - int[] bits = new int[this.domain]; - Symbol symbol = this.symbols[integer]; - if (symbol.integer != integer) { - return false; - } - int i = 0; - while (true) { - Symbol back = symbol.back; - if (back == null) { - break; - } - if (back.zero == symbol) { - bits[i] = 0; - } else if (back.one == symbol) { - bits[i] = 1; - } else { - return false; - } - i += 1; - symbol = back; - } - if (symbol != this.table) { - return false; - } - this.width = 0; - symbol = this.table; - while (symbol.integer == none) { - i -= 1; - symbol = bits[i] != 0 ? symbol.one : symbol.zero; - } - return symbol.integer == integer && i == 0; - } - - /** - * Compare two Huffman tables. - */ - public boolean postMortem(PostMortem pm) { - -// Go through every integer in the domain, generating its bit sequence, and -// then prove that that bit sequence produces the same integer. - - for (int integer = 0; integer < this.domain; integer += 1) { - if (!postMortem(integer)) { - JSONzip.log("\nBad huff "); - JSONzip.logchar(integer, integer); - return false; - } - } - return this.table.postMortem(((Huff) pm).table); - } - - /** - * Read bits until a symbol can be identified. The weight of the read - * symbol will be incremented. - * - * @param bitreader - * The source of bits. - * @return The integer value of the symbol. - * @throws JSONException - */ - public int read(BitReader bitreader) throws JSONException { - try { - this.width = 0; - Symbol symbol = this.table; - while (symbol.integer == none) { - this.width += 1; - symbol = bitreader.bit() ? symbol.one : symbol.zero; - } - tick(symbol.integer); - if (JSONzip.probe) { - JSONzip.logchar(symbol.integer, this.width); - } - return symbol.integer; - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Increase the weight associated with a value by 1. - * - * @param value - * The number of the symbol to tick - */ - public void tick(int value) { - if (this.toLearn > 0) { - this.toLearn -= 1; - this.symbols[value].weight += 1; - this.upToDate = false; - } - } - - /** - * Recur from a symbol back, emitting bits. We recur before emitting to - * make the bits come out in the right order. - * - * @param symbol - * The symbol to write. - * @param bitwriter - * The bitwriter to write it to. - * @throws JSONException - */ - private void write(Symbol symbol, BitWriter bitwriter) - throws JSONException { - try { - Symbol back = symbol.back; - if (back != null) { - this.width += 1; - write(back, bitwriter); - if (back.zero == symbol) { - bitwriter.zero(); - } else { - bitwriter.one(); - } - } - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Write the bits corresponding to a symbol. The weight of the symbol will - * be incremented. - * - * @param value - * The number of the symbol to write - * @param bitwriter - * The destination of the bits. - * @throws JSONException - */ - public void write(int value, BitWriter bitwriter) throws JSONException { - this.width = 0; - write(this.symbols[value], bitwriter); - tick(value); - if (JSONzip.probe) { - JSONzip.logchar(value, this.width); - } - } -} diff --git a/zip/JSONzip.java b/zip/JSONzip.java deleted file mode 100644 index d8e3ac652..000000000 --- a/zip/JSONzip.java +++ /dev/null @@ -1,255 +0,0 @@ -package org.json.zip; - -/* - Copyright (c) 2013 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. - */ - -/** - * JSONzip is a binary-encoded JSON dialect. It is designed to compress the - * messages in a session in bandwidth constrained applications, such as mobile. - * - * JSONzip is adaptive, so with each message seen, it should improve its - * compression. It minimizes JSON's overhead, reducing punctuation - * to a small number of bits. It uses Huffman encoding to reduce the average - * size of characters. It uses caches (or Keeps) to keep recently seen strings - * and values, so repetitive content (such as object keys) can be - * substantially reduced. It uses a character encoding called Kim (Keep it - * minimal) that is smaller than UTF-8 for most East European, African, and - * Asian scripts. - * - * JSONzip tends to reduce most content by about half. If there is a lot of - * recurring information, the reduction can be much more dramatic. - * - * FOR EVALUATION PURPOSES ONLY. THIS PACKAGE HAS NOT YET BEEN TESTED - * ADEQUATELY FOR PRODUCTION USE. - * - * @author JSON.org - * @version 2014-05-20 - */ -public abstract class JSONzip implements None, PostMortem { - /** - * The characters in JSON numbers can be reduced to 4 bits each. - */ - public static final byte[] bcd = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-', '+', 'E' - }; - - /** - * The end of string code. - */ - public static final int end = 256; - - /** - * The end of number code. - */ - public static final int endOfNumber = bcd.length; - - /** - * The first positive integer that cannot be encoded in 4 bits. - */ - public static final long int4 = 16; - - /** - * The first positive integer that cannot be encoded in 7 bits. - */ - public static final long int7 = 144; - - /** - * The first positive integer that cannot be encoded in 14 bits. - */ - public static final long int14 = 16528; - - /** - * The package supports tracing for debugging. - */ - public static final boolean probe = false; - - /** - * The value code for an empty object. - */ - public static final int zipEmptyObject = 0; - - /** - * The value code for an empty array. - */ - public static final int zipEmptyArray = 1; - - /** - * The value code for true. - */ - public static final int zipTrue = 2; - - /** - * The value code for false. - */ - public static final int zipFalse = 3; - - /** - * The value code for null. - */ - public static final int zipNull = 4; - - /** - * The value code for a non-empty object. - */ - public static final int zipObject = 5; - - /** - * The value code for an array with a string as its first element. - */ - public static final int zipArrayString = 6; - - /** - * The value code for an array with a non-string value as its first element. - */ - public static final int zipArrayValue = 7; - - /** - * A Huffman encoder for names. - */ - protected final Huff namehuff; - - /** - * A Huffman encoder for names extended bytes. - */ - protected final Huff namehuffext; - - /** - * A place to keep the names (keys). - */ - protected final Keep namekeep; - - /** - * A Huffman encoder for string values. - */ - protected final Huff stringhuff; - - /** - * A Huffman encoder for string values extended bytes. - */ - protected final Huff stringhuffext; - - /** - * A place to keep the strings. - */ - protected final Keep stringkeep; - - /** - * A place to keep the values. - */ - protected final Keep valuekeep; - - /** - * Initialize the data structures. - */ - protected JSONzip() { - this.namehuff = new Huff(end + 1); - this.namehuffext = new Huff(end + 1); - this.namekeep = new Keep(9); - this.stringhuff = new Huff(end + 1); - this.stringhuffext = new Huff(end + 1); - this.stringkeep = new Keep(11); - this.valuekeep = new Keep(10); - } - - /** - * Generate the Huffman tables. - */ - protected void generate() { - this.namehuff.generate(); - this.namehuffext.generate(); - this.stringhuff.generate(); - this.stringhuffext.generate(); - } - - /** - * Write an end-of-line to the console. - */ - static void log() { - log("\n"); - } - - /** - * Write an integer to the console. - * - * @param integer The integer to write to the log. - */ - static void log(int integer) { - log(integer + " "); - } - - /** - * Write two integers, separated by ':' to the console. - * The second integer is suppressed if it is 1. - * - * @param integer The integer to write to the log. - * @param width The width of the integer in bits. - */ - static void log(int integer, int width) { - if (width == 1) { - log(integer); - } else { - log(integer + ":" + width + " "); - } - } - - /** - * Write a string to the console. - * - * @param string The string to be written to the log. - */ - static void log(String string) { - System.out.print(string); - } - - /** - * Write a character or its code to the console. - * - * @param integer The charcode to be written to the log. - * @param width The width of the charcode in bits. - */ - static void logchar(int integer, int width) { - if (integer > ' ' && integer <= '}') { - log("'" + (char) integer + "':" + width + " "); - } else { - log(integer, width); - } - } - - /** - * This method is used for testing the implementation of JSONzip. It is not - * suitable for any other purpose. It is used to compare a Compressor and a - * Decompressor, verifying that the data structures that were built during - * zipping and unzipping were the same. - * - * @return true if the structures match. - */ - public boolean postMortem(PostMortem pm) { - JSONzip that = (JSONzip) pm; - return this.namehuff.postMortem(that.namehuff) - && this.namekeep.postMortem(that.namekeep) - && this.stringkeep.postMortem(that.stringkeep) - && this.stringhuff.postMortem(that.stringhuff) - && this.valuekeep.postMortem(that.valuekeep); - } -} diff --git a/zip/Keep.java b/zip/Keep.java deleted file mode 100644 index bc647b6a0..000000000 --- a/zip/Keep.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.json.zip; - -import java.util.HashMap; - -import org.json.Kim; - -/* - Copyright (c) 2013 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. - */ - -/** - * A keep is a data structure that associates strings (or substrings) with - * numbers. This allows the sending of small integers instead of strings. - * - * @author JSON.org - * @version 2013-05-03 - */ -class Keep implements None, PostMortem { - private int capacity; - protected int length; - private Object[] list; - private HashMap map; - private int power; - private long[] ticks; - - public Keep(int bits) { - this.capacity = 1 << bits; - this.length = 0; - this.power = 0; - this.ticks = new long[this.capacity]; - this.list = new Object[this.capacity]; - this.map = new HashMap(this.capacity); - } - - /** - * When an item ages, its use count is reduced by at least half. - * - * @param ticks - * The current use count of an item. - * @return The new use count for that item. - */ - public static long age(long ticks) { - return ticks >= 32 ? 16 : ticks / 2; - } - - /** - * Return the number of bits required to contain an integer based on the - * current length of the keep. As the keep fills up, the number of bits - * required to identify one of its items goes up. - */ - public int bitsize() { - while (1 << this.power < this.length) { - this.power += 1; - } - return this.power; - } - - /** - * Increase the usage count on an integer value. - */ - public void tick(int integer) { - this.ticks[integer] += 1; - } - - /** - * Compact the keep. A keep may contain at most this.capacity elements. - * The keep contents can be reduced by deleting all elements with low use - * counts, and by reducing the use counts of the survivors. - */ - private void compact() { - int from = 0; - int to = 0; - while (from < this.capacity) { - Object key = this.list[from]; - long usage = age(this.ticks[from]); - if (usage > 0) { - this.ticks[to] = usage; - this.list[to] = key; - this.map.put(key, to); - to += 1; - } else { - this.map.remove(key); - } - from += 1; - } - if (to < this.capacity) { - this.length = to; - } else { - this.map.clear(); - this.length = 0; - } - this.power = 0; - } - - /** - * Find the integer value associated with this key, or nothing if this key - * is not in the keep. - * - * @param key - * An object. - * @return An integer - */ - public int find(Object key) { - Object o = this.map.get(key); - return o instanceof Integer ? ((Integer) o).intValue() : none; - } - - public boolean postMortem(PostMortem pm) { - Keep that = (Keep) pm; - if (this.length != that.length) { - JSONzip.log(this.length + " <> " + that.length); - return false; - } - for (int i = 0; i < this.length; i += 1) { - boolean b; - if (this.list[i] instanceof Kim) { - b = this.list[i].equals(that.list[i]); - } else { - Object o = this.list[i]; - Object q = that.list[i]; - if (o instanceof Number) { - o = o.toString(); - } - if (q instanceof Number) { - q = q.toString(); - } - b = o.equals(q); - } - if (!b) { - JSONzip.log("\n[" + i + "]\n " + this.list[i] + "\n " - + that.list[i] + "\n " + this.ticks[i] + "\n " - + that.ticks[i]); - return false; - } - } - return true; - } - - /** - * Register a value in the keep. Compact the keep if it is full. The next - * time this value is encountered, its integer can be sent instead. - * @param value A value. - */ - public void register(Object value) { - if (JSONzip.probe) { - int integer = find(value); - if (integer >= 0) { - JSONzip.log("\nDuplicate key " + value); - } - } - if (this.length >= this.capacity) { - compact(); - } - this.list[this.length] = value; - this.map.put(value, this.length); - this.ticks[this.length] = 1; - if (JSONzip.probe) { - JSONzip.log("<" + this.length + " " + value + "> "); - } - this.length += 1; - } - - /** - * Return the value associated with the integer. - * @param integer The number of an item in the keep. - * @return The value. - */ - public Object value(int integer) { - return this.list[integer]; - } -} diff --git a/zip/None.java b/zip/None.java deleted file mode 100644 index 818e68d8f..000000000 --- a/zip/None.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.json.zip; - -/** - * None is an interface that makes the constant none (short for - * negative one or long for -1) available to any class that implements it. - * The none value is used to stand for an integer that is not an integer, - * such as the negative result of a search. - */ -public interface None { - /** - * Negative One. - */ - public static final int none = -1; - -} diff --git a/zip/PostMortem.java b/zip/PostMortem.java deleted file mode 100644 index 0f220ee48..000000000 --- a/zip/PostMortem.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.json.zip; - -/* - Copyright (c) 2013 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. - */ - -/** - * The PostMortem interface allows for testing the internal state of JSONzip - * processors. Testing that JSONzip can compress an object and reproduce a - * corresponding object is not sufficient. Complete testing requires that the - * same internal data structures were constructed on both ends. If those - * structures are not exactly equivalent, then it is likely that the - * implementations are not correct, even if conventional tests are passed. - * - * PostMortem allows for testing of deep structures without breaking - * encapsulation. - */ -public interface PostMortem { - /** - * Determine if two objects are equivalent. - * - * @param pm - * Another object of the same type. - * @return true if they match. - */ - public boolean postMortem(PostMortem pm); -} diff --git a/zip/README b/zip/README deleted file mode 100644 index 93e6470b7..000000000 --- a/zip/README +++ /dev/null @@ -1,2 +0,0 @@ -FOR EVALUATION PURPOSES ONLY. THIS PACKAGE HAS NOT BEEN TESTED ADEQUATELY FOR -PRODUCTION USE. diff --git a/zip/Unzipper.java b/zip/Unzipper.java deleted file mode 100644 index a7c308eda..000000000 --- a/zip/Unzipper.java +++ /dev/null @@ -1,310 +0,0 @@ -package org.json.zip; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.Kim; - -/* - Copyright (c) 2012 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. - */ - -/** - * JSONzip is a binary compression scheme for JSON text. - * - * @author JSON.org - * @version 2014-05-03 - */ - -public class Unzipper extends JSONzip { - - /** - * A decoder reads bits from a BitReader. - */ - BitReader bitreader; - - /** - * Create a new unzipper. It may be used for an entire session or - * subsession. - * - * @param bitreader - * The bitreader that this decoder will read from. - */ - public Unzipper(BitReader bitreader) { - super(); - this.bitreader = bitreader; - } - - /** - * Read one bit. - * - * @return true if 1, false if 0. - * @throws JSONException - */ - private boolean bit() throws JSONException { - boolean value; - try { - value = this.bitreader.bit(); - if (probe) { - log(value ? 1 : 0); - } - return value; - } catch (Throwable e) { - throw new JSONException(e); - } - - } - - /** - * Read enough bits to obtain an integer from the keep, and increase that - * integer's weight. - * - * @param keep The keep providing the context. - * @param bitreader The bitreader that is the source of bits. - * @return The value associated with the number. - * @throws JSONException - */ - private Object getAndTick(Keep keep, BitReader bitreader) - throws JSONException { - try { - int width = keep.bitsize(); - int integer = bitreader.read(width); - Object value = keep.value(integer); - if (JSONzip.probe) { - JSONzip.log("\"" + value + "\""); - JSONzip.log(integer, width); - } - if (integer >= keep.length) { - throw new JSONException("Deep error."); - } - keep.tick(integer); - return value; - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * The pad method skips the bits that padded a stream to fit some - * allocation. pad(8) will skip over the remainder of a byte. - * - * @param width The width of the pad field in bits. - * @return true if all of the padding bits were zero. - * @throws JSONException - */ - public boolean pad(int width) throws JSONException { - try { - return this.bitreader.pad(width); - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Read an integer, specifying its width in bits. - * - * @param width - * 0 to 32. - * @return An unsigned integer. - * @throws JSONException - */ - private int read(int width) throws JSONException { - try { - int value = this.bitreader.read(width); - if (probe) { - log(value, width); - } - return value; - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Read Huffman encoded characters into a keep. - * @param huff A Huffman decoder. - * @param ext A Huffman decoder for the extended bytes. - * @param keep The keep that will receive the kim. - * @return The string that was read. - * @throws JSONException - */ - private String read(Huff huff, Huff ext, Keep keep) throws JSONException { - Kim kim; - int at = 0; - int allocation = 256; - byte[] bytes = new byte[allocation]; - if (bit()) { - return getAndTick(keep, this.bitreader).toString(); - } - while (true) { - if (at >= allocation) { - allocation *= 2; - bytes = java.util.Arrays.copyOf(bytes, allocation); - } - int c = huff.read(this.bitreader); - if (c == end) { - break; - } - while ((c & 128) == 128) { - bytes[at] = (byte) c; - at += 1; - c = ext.read(this.bitreader); - } - bytes[at] = (byte) c; - at += 1; - } - if (at == 0) { - return ""; - } - kim = new Kim(bytes, at); - keep.register(kim); - return kim.toString(); - } - - /** - * Read a JSONArray. - * - * @param stringy - * true if the first element is a string. - * @throws JSONException - */ - private JSONArray readArray(boolean stringy) throws JSONException { - JSONArray jsonarray = new JSONArray(); - jsonarray.put(stringy - ? read(this.stringhuff, this.stringhuffext, this.stringkeep) - : readValue()); - while (true) { - if (probe) { - log(); - } - if (!bit()) { - if (!bit()) { - return jsonarray; - } - jsonarray.put(stringy - ? readValue() - : read(this.stringhuff, this.stringhuffext, - this.stringkeep)); - } else { - jsonarray.put(stringy - ? read(this.stringhuff, this.stringhuffext, - this.stringkeep) - : readValue()); - } - } - } - - /** - * Read a JSON value. The type of value is determined by the next 3 bits. - * - * @return The read value. - * @throws JSONException - */ - private Object readJSON() throws JSONException { - switch (read(3)) { - case zipObject: - return readObject(); - case zipArrayString: - return readArray(true); - case zipArrayValue: - return readArray(false); - case zipEmptyObject: - return new JSONObject(); - case zipEmptyArray: - return new JSONArray(); - case zipTrue: - return Boolean.TRUE; - case zipFalse: - return Boolean.FALSE; - default: - return JSONObject.NULL; - } - } - - private JSONObject readObject() throws JSONException { - JSONObject jsonobject = new JSONObject(); - while (true) { - if (probe) { - log(); - } - String name = read(this.namehuff, this.namehuffext, this.namekeep); - if (jsonobject.opt(name) != null) { - throw new JSONException("Duplicate key."); - } - jsonobject.put(name, !bit() - ? read(this.stringhuff, this.stringhuffext, this.stringkeep) - : readValue()); - if (!bit()) { - return jsonobject; - } - } - } - - private Object readValue() throws JSONException { - switch (read(2)) { - case 0: - int nr_bits = !bit() ? 4 : !bit() ? 7 : 14; - int integer = read(nr_bits); - switch (nr_bits) { - case 7: - integer += int4; - break; - case 14: - integer += int7; - break; - } - return integer; - case 1: - byte[] bytes = new byte[256]; - int length = 0; - while (true) { - int c = read(4); - if (c == endOfNumber) { - break; - } - bytes[length] = bcd[c]; - length += 1; - } - Object value; - try { - value = JSONObject.stringToValue(new String(bytes, 0, length, - "US-ASCII")); - } catch (java.io.UnsupportedEncodingException e) { - throw new JSONException(e); - } - this.valuekeep.register(value); - return value; - case 2: - return getAndTick(this.valuekeep, this.bitreader); - case 3: - return readJSON(); - default: - throw new JSONException("Impossible."); - } - } - - public Object decode() throws JSONException { - generate(); - return readJSON(); - } -} diff --git a/zip/Zipper.java b/zip/Zipper.java deleted file mode 100644 index 48b4f1acb..000000000 --- a/zip/Zipper.java +++ /dev/null @@ -1,481 +0,0 @@ -package org.json.zip; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.Kim; - -/* - Copyright (c) 2013 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. - */ - -/** - * JSONzip is a binary compression scheme for JSON text. - * - * @author JSON.org - * @version 2014-05-03 - */ - -/** - * An encoder implements the compression behavior of JSONzip. It provides a - * zip method that takes a JSONObject or JSONArray and delivers a stream of - * bits to a BitWriter. - * - * FOR EVALUATION PURPOSES ONLY. THIS PACKAGE HAS NOT BEEN TESTED ADEQUATELY - * FOR PRODUCTION USE. - */ -public class Zipper extends JSONzip { - - /** - * An encoder outputs to a BitWriter. - */ - final BitWriter bitwriter; - - /** - * Create a new encoder. It may be used for an entire session or - * subsession. - * - * @param bitwriter - * The BitWriter this encoder will output to. - * Don't forget to flush. - */ - public Zipper(BitWriter bitwriter) { - super(); - this.bitwriter = bitwriter; - } - - /** - * Return a 4 bit code for a character in a JSON number. The digits '0' to - * '9' get the codes 0 to 9. '.' is 10, '-' is 11, '+' is 12, and 'E' or - * 'e' is 13. - * - * @param digit - * An ASCII character from a JSON number. - * @return The number code. - */ - private static int bcd(char digit) { - if (digit >= '0' && digit <= '9') { - return digit - '0'; - } - switch (digit) { - case '.': - return 10; - case '-': - return 11; - case '+': - return 12; - default: - return 13; - } - } - - /** - * Finish the final byte and flush the bitwriter. This does the same thing - * as pad(8). - * - * @throws JSONException - */ - public void flush() throws JSONException { - pad(8); - } - - /** - * Output a one bit. - * - * @throws JSONException - */ - private void one() throws JSONException { - write(1, 1); - } - - /** - * Pad the output to fill an allotment of bits. - * - * @param width - * The size of the bit allotment. A value of 8 will complete and - * flush the current byte. If you don't pad, then some of the - * last bits might not be sent to the Output Stream. - * @throws JSONException - */ - public void pad(int width) throws JSONException { - try { - this.bitwriter.pad(width); - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Write a number, using the number of bits necessary to hold the number. - * - * @param integer - * The value to be encoded. - * @param width - * The number of bits to encode the value, between 0 and 32. - * @throws JSONException - */ - private void write(int integer, int width) throws JSONException { - try { - this.bitwriter.write(integer, width); - if (probe) { - log(integer, width); - } - } catch (Throwable e) { - throw new JSONException(e); - } - } - - /** - * Write an integer with Huffman encoding. The bit pattern that is written - * will be determined by the Huffman encoder. - * - * @param integer - * The value to be written. - * @param huff - * The Huffman encoder. - * @throws JSONException - */ - private void write(int integer, Huff huff) throws JSONException { - huff.write(integer, this.bitwriter); - } - - /** - * Write each of the bytes in a kim with Huffman encoding. - * - * @param kim - * A kim containing the bytes to be written. - * @param huff - * The Huffman encoder. - * @param ext - * The Huffman encoder for the extended bytes. - * @throws JSONException - */ - private void write(Kim kim, Huff huff, Huff ext) throws JSONException { - for (int at = 0; at < kim.length; at += 1) { - int c = kim.get(at); - write(c, huff); - while ((c & 128) == 128) { - at += 1; - c = kim.get(at); - write(c, ext); - } - } - } - - /** - * Write an integer, using the number of bits necessary to hold the number - * as determined by its keep, and increment its usage count in the keep. - * - * @param integer - * The value to be encoded. - * @param keep - * The Keep that the integer is one of. - * @throws JSONException - */ - private void write(int integer, Keep keep) throws JSONException { - int width = keep.bitsize(); - keep.tick(integer); - if (probe) { - log("\"" + keep.value(integer) + "\""); - } - write(integer, width); - } - - /** - * Write a JSON Array. - * - * @param jsonarray The JSONArray to write. - * @throws JSONException If the write fails. - */ - private void write(JSONArray jsonarray) throws JSONException { - -// JSONzip has three encodings for arrays: -// The array is empty (zipEmptyArray). -// First value in the array is a string (zipArrayString). -// First value in the array is not a string (zipArrayValue). - - boolean stringy = false; - int length = jsonarray.length(); - if (length == 0) { - write(zipEmptyArray, 3); - } else { - Object value = jsonarray.get(0); - if (value == null) { - value = JSONObject.NULL; - } - if (value instanceof String) { - stringy = true; - write(zipArrayString, 3); - writeString((String) value); - } else { - write(zipArrayValue, 3); - writeValue(value); - } - for (int i = 1; i < length; i += 1) { - if (probe) { - log(); - } - value = jsonarray.get(i); - if (value == null) { - value = JSONObject.NULL; - } - if (value instanceof String != stringy) { - zero(); - } - one(); - if (value instanceof String) { - writeString((String) value); - } else { - writeValue(value); - } - } - zero(); - zero(); - - } - } - - /** - * Write a JSON value. - * - * @param value - * One of these types: JSONObject, JSONArray (or Map or - * Collection or array), Number (or Integer or Long or Double), - * or String, or Boolean, or JSONObject.NULL, or null. - * @throws JSONException - */ - private void writeJSON(Object value) throws JSONException { - if (JSONObject.NULL.equals(value)) { - write(zipNull, 3); - } else if (Boolean.FALSE.equals(value)) { - write(zipFalse, 3); - } else if (Boolean.TRUE.equals(value)) { - write(zipTrue, 3); - } else { - if (value instanceof Map) { - value = new JSONObject((Map) value); - } else if (value instanceof Collection) { - value = new JSONArray((Collection) value); - } else if (value.getClass().isArray()) { - value = new JSONArray(value); - } - if (value instanceof JSONObject) { - write((JSONObject) value); - } else if (value instanceof JSONArray) { - write((JSONArray) value); - } else { - throw new JSONException("Unrecognized object"); - } - } - } - - /** - * Write the name of an object property. Names have their own Keep and - * Huffman encoder because they are expected to be a more restricted set. - * - * @param name The name string. - * @throws JSONException - */ - private void writeName(String name) throws JSONException { - -// If this name has already been registered, then emit its integer and -// increment its usage count. - - Kim kim = new Kim(name); - int integer = this.namekeep.find(kim); - if (integer != none) { - one(); - write(integer, this.namekeep); - } else { - -// Otherwise, emit the string with Huffman encoding, and register it. - - zero(); - write(kim, this.namehuff, this.namehuffext); - write(end, namehuff); - this.namekeep.register(kim); - } - } - - /** - * Write a JSON object. - * - * @param jsonobject The JSONObject to be written. - * @throws JSONException - */ - private void write(JSONObject jsonobject) throws JSONException { - -// JSONzip has two encodings for objects: Empty Objects (zipEmptyObject) and -// non-empty objects (zipObject). - - boolean first = true; - Iterator keys = jsonobject.keys(); - while (keys.hasNext()) { - if (probe) { - log(); - } - Object key = keys.next(); - if (key instanceof String) { - if (first) { - first = false; - write(zipObject, 3); - } else { - one(); - } - writeName((String) key); - Object value = jsonobject.get((String) key); - if (value instanceof String) { - zero(); - writeString((String) value); - } else { - one(); - writeValue(value); - } - } - } - if (first) { - write(zipEmptyObject, 3); - } else { - zero(); - } - } - - /** - * Write a string. - * - * @param string The string to write. - * @throws JSONException - */ - private void writeString(String string) throws JSONException { - -// Special case for empty strings. - - if (string.length() == 0) { - zero(); - write(end, this.stringhuff); - } else { - Kim kim = new Kim(string); - -// Look for the string in the strings keep. If it is found, emit its -// integer and count that as a use. - - int integer = this.stringkeep.find(kim); - if (integer != none) { - one(); - write(integer, this.stringkeep); - } else { - -// But if it is not found, emit the string's characters. Register the string -// so that a later lookup can succeed. - - zero(); - write(kim, this.stringhuff, this.stringhuffext); - write(end, this.stringhuff); - this.stringkeep.register(kim); - } - } - } - - /** - * Write a value. - * - * @param value - * One of these types: Boolean, Number, etc. - * @throws JSONException - */ - private void writeValue(Object value) throws JSONException { - if (value instanceof Number) { - String string = JSONObject.numberToString((Number) value); - int integer = this.valuekeep.find(string); - if (integer != none) { - write(2, 2); - write(integer, this.valuekeep); - return; - } - if (value instanceof Integer || value instanceof Long) { - long longer = ((Number) value).longValue(); - if (longer >= 0 && longer < int14) { - write(0, 2); - if (longer < int4) { - zero(); - write((int) longer, 4); - return; - } - one(); - if (longer < int7) { - zero(); - write((int)(longer - int4), 7); - return; - } - one(); - write((int)(longer - int7), 14); - return; - } - } - write(1, 2); - for (int i = 0; i < string.length(); i += 1) { - write(bcd(string.charAt(i)), 4); - } - write(endOfNumber, 4); - this.valuekeep.register(string); - } else { - write(3, 2); - writeJSON(value); - } - } - - /** - * Output a zero bit. - * - * @throws JSONException - */ - private void zero() throws JSONException { - write(0, 1); - } - - /** - * Encode a JSONObject. - * - * @param jsonobject The JSONObject. - * @throws JSONException - */ - public void encode(JSONObject jsonobject) throws JSONException { - generate(); - writeJSON(jsonobject); - } - - /** - * Encode a JSONArray. - * - * @param jsonarray The JSONArray. - * @throws JSONException - */ - public void encode(JSONArray jsonarray) throws JSONException { - generate(); - writeJSON(jsonarray); - } -} From d6ba31819c48db39be068c8b3b1fa985df09ea65 Mon Sep 17 00:00:00 2001 From: stleary Date: Sun, 19 Apr 2015 17:53:40 -0500 Subject: [PATCH 05/59] fix toString(JSONArray) to emit object.toString() values --- JSONML.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/JSONML.java b/JSONML.java index 20e0be5fa..42027cb00 100755 --- a/JSONML.java +++ b/JSONML.java @@ -373,6 +373,8 @@ public static String toString(JSONArray ja) throws JSONException { sb.append(toString((JSONObject)object)); } else if (object instanceof JSONArray) { sb.append(toString((JSONArray)object)); + } else { + sb.append(object.toString()); } } } while (i < length); From 37f099ed4b19cd155cbedb9e9292bc3fc5794e41 Mon Sep 17 00:00:00 2001 From: stleary Date: Fri, 1 May 2015 12:52:23 -0500 Subject: [PATCH 06/59] s/covert/convert/ --- CDL.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CDL.java b/CDL.java index 995b1d478..8520e862d 100755 --- a/CDL.java +++ b/CDL.java @@ -26,7 +26,7 @@ of this software and associated documentation files (the "Software"), to deal /** * This provides static methods to convert comma delimited text into a - * JSONArray, and to covert a JSONArray into comma delimited text. Comma + * JSONArray, and to convert a JSONArray into comma delimited text. Comma * delimited text is a very popular format for data interchange. It is * understood by most database, spreadsheet, and organizer programs. *

@@ -41,7 +41,7 @@ of this software and associated documentation files (the "Software"), to deal * The names for the elements in the JSONObjects can be taken from the names * in the first row. * @author JSON.org - * @version 2014-05-03 + * @version 2015-05-01 */ public class CDL { From a851bf095196aab53b7406a55f2f7c0125413a60 Mon Sep 17 00:00:00 2001 From: stleary Date: Tue, 5 May 2015 20:11:28 -0500 Subject: [PATCH 07/59] Replaced tab chars, updated versions --- JSONObject.java | 32 ++++++++++++++++++++++---------- Property.java | 4 ++-- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/JSONObject.java b/JSONObject.java index d66623110..e28c9cd37 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -91,7 +91,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2014-05-03 + * @version 2015-05-05 */ public class JSONObject { /** @@ -298,7 +298,7 @@ public JSONObject(Object bean) { */ public JSONObject(Object object, String names[]) { this(); - Class c = object.getClass(); + Class c = object.getClass(); for (int i = 0; i < names.length; i += 1) { String name = names[i]; try { @@ -631,7 +631,7 @@ public static String[] getNames(Object object) { if (object == null) { return null; } - Class klass = object.getClass(); + Class klass = object.getClass(); Field[] fields = klass.getFields(); int length = fields.length; if (length == 0) { @@ -981,7 +981,7 @@ public String optString(String key, String defaultValue) { } private void populateMap(Object bean) { - Class klass = bean.getClass(); + Class klass = bean.getClass(); // If klass is a System class then set includeSuperClass to false. @@ -1512,10 +1512,14 @@ public static String valueToString(Object value) throws JSONException { return value.toString(); } if (value instanceof Map) { - return new JSONObject((Map)value).toString(); + @SuppressWarnings("unchecked") + Map map = (Map) value; + return new JSONObject(map).toString(); } if (value instanceof Collection) { - return new JSONArray((Collection) value).toString(); + @SuppressWarnings("unchecked") + Collection coll = (Collection) value; + return new JSONArray(coll).toString(); } if (value.getClass().isArray()) { return new JSONArray(value).toString(); @@ -1551,13 +1555,17 @@ public static Object wrap(Object object) { } if (object instanceof Collection) { - return new JSONArray((Collection) object); + @SuppressWarnings("unchecked") + Collection coll = (Collection) object; + return new JSONArray(coll); } if (object.getClass().isArray()) { return new JSONArray(object); } if (object instanceof Map) { - return new JSONObject((Map) object); + @SuppressWarnings("unchecked") + Map map = (Map) object; + return new JSONObject(map); } Package objectPackage = object.getClass().getPackage(); String objectPackageName = objectPackage != null ? objectPackage @@ -1595,9 +1603,13 @@ static final Writer writeValue(Writer writer, Object value, } else if (value instanceof JSONArray) { ((JSONArray) value).write(writer, indentFactor, indent); } else if (value instanceof Map) { - new JSONObject((Map) value).write(writer, indentFactor, indent); + @SuppressWarnings("unchecked") + Map map = (Map) value; + new JSONObject(map).write(writer, indentFactor, indent); } else if (value instanceof Collection) { - new JSONArray((Collection) value).write(writer, indentFactor, + @SuppressWarnings("unchecked") + Collection coll = (Collection) value; + new JSONArray(coll).write(writer, indentFactor, indent); } else if (value.getClass().isArray()) { new JSONArray(value).write(writer, indentFactor, indent); diff --git a/Property.java b/Property.java index 8122241e9..73ddb1287 100644 --- a/Property.java +++ b/Property.java @@ -31,7 +31,7 @@ of this software and associated documentation files (the "Software"), to deal /** * Converts a Property file data into JSONObject and back. * @author JSON.org - * @version 2014-05-03 + * @version 2015-05-05 */ public class Property { /** @@ -43,7 +43,7 @@ public class Property { public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { JSONObject jo = new JSONObject(); if (properties != null && !properties.isEmpty()) { - Enumeration enumProperties = properties.propertyNames(); + Enumeration enumProperties = properties.propertyNames(); while(enumProperties.hasMoreElements()) { String name = (String)enumProperties.nextElement(); jo.put(name, properties.getProperty(name)); From d2cd1a8df5cd6392650f455a5df844ec55c3e1dc Mon Sep 17 00:00:00 2001 From: stleary Date: Thu, 4 Jun 2015 22:26:16 -0500 Subject: [PATCH 08/59] iterable --- JSONArray.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 3f05548d5..deede035a 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -75,9 +75,9 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2014-05-03 + * @version 2015-06-04 */ -public class JSONArray { +public class JSONArray implements Iterable { /** * The arrayList where the JSONArray's properties are kept. @@ -179,6 +179,11 @@ public JSONArray(Object array) throws JSONException { } } + @Override + public Iterator iterator() { + return myArrayList.iterator(); + } + /** * Get the object value associated with an index. * From 8bc62cc34c071a73c339a878b116bcb1f80d69d2 Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 20 Jun 2015 13:26:55 -0500 Subject: [PATCH 09/59] support for BigInteger and BigDecimal --- JSONObject.java | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/JSONObject.java b/JSONObject.java index e28c9cd37..6b8ce6bcd 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -30,6 +30,7 @@ of this software and associated documentation files (the "Software"), to deal import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.math.*; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; @@ -503,6 +504,46 @@ public boolean getBoolean(String key) throws JSONException { + "] is not a Boolean."); } + /** + * Get the BigInteger value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value cannot + * be converted to BigInteger. + */ + public BigInteger getBigInteger(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigInteger."); + } + } + + /** + * Get the BigDecimal value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value + * cannot be converted to BigDecimal. + */ + public BigDecimal getBigDecimal(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigDecimal."); + } + } + /** * Get the double value associated with a key. * @@ -688,6 +729,10 @@ public JSONObject increment(String key) throws JSONException { Object value = this.opt(key); if (value == null) { this.put(key, 1); + } else if (value instanceof BigInteger) { + this.put(key, ((BigInteger)value).add(BigInteger.ONE)); + } else if (value instanceof BigDecimal) { + this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); } else if (value instanceof Integer) { this.put(key, (Integer) value + 1); } else if (value instanceof Long) { @@ -843,6 +888,44 @@ public double optDouble(String key) { return this.optDouble(key, Double.NaN); } + /** + * Get an optional BigInteger associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigInteger optBigInteger(String key, BigInteger defaultValue) { + try { + return this.getBigInteger(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional BigDecimal associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { + try { + return this.getBigDecimal(key); + } catch (Exception e) { + return defaultValue; + } + } + /** * Get an optional double associated with a key, or the defaultValue if * there is no such key or if its value is not a number. If the value is a From 5d6bf7d132e3ac0a9096dd60b5408f826f59b518 Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 20 Jun 2015 15:18:22 -0500 Subject: [PATCH 10/59] support BigInteger and BigDecimal --- JSONObject.java | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/JSONObject.java b/JSONObject.java index e28c9cd37..6b8ce6bcd 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -30,6 +30,7 @@ of this software and associated documentation files (the "Software"), to deal import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.math.*; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; @@ -503,6 +504,46 @@ public boolean getBoolean(String key) throws JSONException { + "] is not a Boolean."); } + /** + * Get the BigInteger value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value cannot + * be converted to BigInteger. + */ + public BigInteger getBigInteger(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigInteger."); + } + } + + /** + * Get the BigDecimal value associated with a key. + * + * @param key + * A key string. + * @return The numeric value. + * @throws JSONException + * if the key is not found or if the value + * cannot be converted to BigDecimal. + */ + public BigDecimal getBigDecimal(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigDecimal."); + } + } + /** * Get the double value associated with a key. * @@ -688,6 +729,10 @@ public JSONObject increment(String key) throws JSONException { Object value = this.opt(key); if (value == null) { this.put(key, 1); + } else if (value instanceof BigInteger) { + this.put(key, ((BigInteger)value).add(BigInteger.ONE)); + } else if (value instanceof BigDecimal) { + this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); } else if (value instanceof Integer) { this.put(key, (Integer) value + 1); } else if (value instanceof Long) { @@ -843,6 +888,44 @@ public double optDouble(String key) { return this.optDouble(key, Double.NaN); } + /** + * Get an optional BigInteger associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigInteger optBigInteger(String key, BigInteger defaultValue) { + try { + return this.getBigInteger(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional BigDecimal associated with a key, or the defaultValue if + * there is no such key or if its value is not a number. If the value is a + * string, an attempt will be made to evaluate it as a number. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { + try { + return this.getBigDecimal(key); + } catch (Exception e) { + return defaultValue; + } + } + /** * Get an optional double associated with a key, or the defaultValue if * there is no such key or if its value is not a number. If the value is a From b39ccc2a67563cd90421d694bb7d0a7e296f9b99 Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 20 Jun 2015 15:20:56 -0500 Subject: [PATCH 11/59] support BigDecimal and BigInteger --- JSONObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONObject.java b/JSONObject.java index 6b8ce6bcd..14f58b821 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-05-05 + * @version 2015-06-20 */ public class JSONObject { /** From a76d7262d11e34c9adb403d76c98db21e0c83bb6 Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 20 Jun 2015 16:20:00 -0500 Subject: [PATCH 12/59] support BigInteger and BigDecimal --- JSONObject.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/JSONObject.java b/JSONObject.java index 14f58b821..682c51369 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -1633,7 +1633,8 @@ public static Object wrap(Object object) { || object instanceof Short || object instanceof Integer || object instanceof Long || object instanceof Boolean || object instanceof Float || object instanceof Double - || object instanceof String) { + || object instanceof String || object instanceof BigInteger + || object instanceof BigDecimal) { return object; } From 6ab6f063c82e1604f2a5af59d4f4a072165ab55b Mon Sep 17 00:00:00 2001 From: stleary Date: Fri, 3 Jul 2015 20:41:47 -0500 Subject: [PATCH 13/59] latest --- JSONArray.java | 43 ++++++++++++++++++++++++++++++++++++++++++- JSONObject.java | 2 +- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index deede035a..22d4ab7ff 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -28,6 +28,7 @@ of this software and associated documentation files (the "Software"), to deal import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; +import java.math.*; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -75,7 +76,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-06-04 + * @version 2015-07-04 */ public class JSONArray implements Iterable { @@ -246,6 +247,46 @@ public double getDouble(int index) throws JSONException { } } + /** + * Get the BigDecimal value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a BigDecimal. + */ + public BigDecimal getBigDecimal (int index) throws JSONException { + Object object = this.get(index); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + + "] could not convert to BigDecimal."); + } + } + + /** + * Get the BigInteger value associated with an index. + * + * @param index + * The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException + * If the key is not found or if the value cannot be converted + * to a BigInteger. + */ + public BigInteger getBigInteger (int index) throws JSONException { + Object object = this.get(index); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + + "] could not convert to BigInteger."); + } + } + /** * Get the int value associated with an index. * diff --git a/JSONObject.java b/JSONObject.java index 14f58b821..24223c5a6 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-06-20 + * @version 2015-07-04 */ public class JSONObject { /** From 410afaff145ba59c4979c0492e2d244ac6e6dfe4 Mon Sep 17 00:00:00 2001 From: stleary Date: Mon, 6 Jul 2015 22:20:19 -0500 Subject: [PATCH 14/59] latest --- JSONArray.java | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/JSONArray.java b/JSONArray.java index 22d4ab7ff..684ed7a05 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -531,6 +531,44 @@ public int optInt(int index, int defaultValue) { } } + /** + * Get the optional BigInteger 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 + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public BigInteger optBigInteger(int index, BigInteger defaultValue) { + try { + return this.getBigInteger(index); + } catch (Exception e) { + return 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. + * + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default value. + * @return The value. + */ + public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { + try { + return this.getBigDecimal(index); + } catch (Exception e) { + return defaultValue; + } + } + /** * Get the optional JSONArray associated with an index. * From 71d9ad2b9909fa5d7fe6fcc85879002628ea9de4 Mon Sep 17 00:00:00 2001 From: stleary Date: Mon, 6 Jul 2015 22:27:10 -0500 Subject: [PATCH 15/59] update version dates --- JSONArray.java | 2 +- JSONObject.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 684ed7a05..b1334db25 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -76,7 +76,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-07-04 + * @version 2015-07-06 */ public class JSONArray implements Iterable { diff --git a/JSONObject.java b/JSONObject.java index ff3f90061..34d5c6c83 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-07-04 + * @version 2015-07-06 */ public class JSONObject { /** From 96b2e3845930ace5fb652a5e561751eb193ff016 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Mon, 20 Jul 2015 10:02:21 -0500 Subject: [PATCH 16/59] Update README --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index 2de22ffc4..925141f9e 100755 --- a/README +++ b/README @@ -71,3 +71,5 @@ 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 From ca3001629a398267fd312ee588cf7408bfe177ef Mon Sep 17 00:00:00 2001 From: stleary Date: Wed, 22 Jul 2015 20:11:07 -0500 Subject: [PATCH 17/59] latest --- JSONArray.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ JSONObject.java | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/JSONArray.java b/JSONArray.java index b1334db25..580691799 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -247,6 +247,31 @@ public double getDouble(int index) throws JSONException { } } + /** + * Get the enum value associated with an index. + * + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @return The enum value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an enum. + */ + public > E getEnum(Class clazz, int index) throws JSONException { + E val = optEnum(clazz, index); + if(val==null) { + // 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()) + + "."); + } + return val; + } + /** * Get the BigDecimal value associated with an index. * @@ -531,6 +556,50 @@ public int optInt(int index, int defaultValue) { } } + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @return The enum value or null if not found + */ + public > E optEnum(Class clazz, int index) { + return this.optEnum(clazz, index, null); + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param index + * The index must be between 0 and length() - 1. + * @param defaultValue + * The default in case the value is not found + * @return The enum value or defaultValue if the value is not found or + * cannot be assigned to clazz + */ + public > E optEnum(Class clazz, int index, E defaultValue) { + try { + Object val = this.opt(index); + if (JSONObject.NULL.equals(val)) { + return defaultValue; + } + if (clazz.isAssignableFrom(val.getClass())) { + // we just checked it! + @SuppressWarnings("unchecked") + E myE = (E) val; + return myE; + } + return Enum.valueOf(clazz, val.toString()); + } catch (IllegalArgumentException | NullPointerException e) { + return defaultValue; + } + } + + /** * Get the optional BigInteger value associated with an index. The * defaultValue is returned if there is no value for the index, or if the diff --git a/JSONObject.java b/JSONObject.java index 34d5c6c83..2bf733be9 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -479,6 +479,31 @@ public Object get(String key) throws JSONException { return object; } + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @return The enum value. + * @throws JSONException + * if the key is not found or if the value cannot be converted + * to an enum. + */ + public > E getEnum(Class clazz, String key) throws JSONException { + E val = optEnum(clazz, key); + if(val==null) { + // 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[" + quote(key) + + "] is not an enum of type " + quote(clazz.getSimpleName()) + + "."); + } + return val; + } + /** * Get the boolean value associated with a key. * @@ -844,6 +869,49 @@ public Object opt(String key) { return key == null ? null : this.map.get(key); } + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @return The enum value or null if not found + */ + public > E optEnum(Class clazz, String key) { + return this.optEnum(clazz, key, null); + } + + /** + * Get the enum value associated with a key. + * + * @param clazz + * The type of enum to retrieve. + * @param key + * A key string. + * @param defaultValue + * The default in case the value is not found + * @return The enum value or defaultValue if the value is not found or + * cannot be assigned to clazz + */ + public > E optEnum(Class clazz, String key, E defaultValue) { + try { + Object val = this.opt(key); + if (NULL.equals(val)) { + return defaultValue; + } + if (clazz.isAssignableFrom(val.getClass())) { + // we just checked it! + @SuppressWarnings("unchecked") + E myE = (E) val; + return myE; + } + return Enum.valueOf(clazz, val.toString()); + } catch (IllegalArgumentException | NullPointerException e) { + return defaultValue; + } + } + /** * Get an optional boolean associated with a key. It returns false if there * is no such key, or if the value is not Boolean.TRUE or the String "true". From 9785b4ff0b2d920ea81aa1303f79d5bfb1485135 Mon Sep 17 00:00:00 2001 From: stleary Date: Wed, 22 Jul 2015 20:16:02 -0500 Subject: [PATCH 18/59] enum support --- JSONArray.java | 8 ++++---- JSONObject.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 580691799..3aaa18563 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -254,7 +254,7 @@ public double getDouble(int index) throws JSONException { * The type of enum to retrieve. * @param index * The index must be between 0 and length() - 1. - * @return The enum value. + * @return The enum value at the index location * @throws JSONException * if the key is not found or if the value cannot be converted * to an enum. @@ -563,7 +563,7 @@ public int optInt(int index, int defaultValue) { * The type of enum to retrieve. * @param index * The index must be between 0 and length() - 1. - * @return The enum value or null if not found + * @return The enum value at the index location or null if not found */ public > E optEnum(Class clazz, int index) { return this.optEnum(clazz, index, null); @@ -578,8 +578,8 @@ public > E optEnum(Class clazz, int index) { * The index must be between 0 and length() - 1. * @param defaultValue * The default in case the value is not found - * @return The enum value or defaultValue if the value is not found or - * cannot be assigned to clazz + * @return The enum value at the index location or defaultValue if + * the value is not found or cannot be assigned to clazz */ public > E optEnum(Class clazz, int index, E defaultValue) { try { diff --git a/JSONObject.java b/JSONObject.java index 2bf733be9..fc7fb81e7 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -486,7 +486,7 @@ public Object get(String key) throws JSONException { * The type of enum to retrieve. * @param key * A key string. - * @return The enum value. + * @return The enum value associated with the key * @throws JSONException * if the key is not found or if the value cannot be converted * to an enum. @@ -876,7 +876,7 @@ public Object opt(String key) { * The type of enum to retrieve. * @param key * A key string. - * @return The enum value or null if not found + * @return The enum value associated with the key or null if not found */ public > E optEnum(Class clazz, String key) { return this.optEnum(clazz, key, null); @@ -891,8 +891,8 @@ public > E optEnum(Class clazz, String key) { * A key string. * @param defaultValue * The default in case the value is not found - * @return The enum value or defaultValue if the value is not found or - * cannot be assigned to clazz + * @return The enum value associated with the key or defaultValue + * if the value is not found or cannot be assigned to clazz */ public > E optEnum(Class clazz, String key, E defaultValue) { try { From 5fc22e32a89698703cacc17952864d0f42660625 Mon Sep 17 00:00:00 2001 From: stleary Date: Wed, 22 Jul 2015 20:18:30 -0500 Subject: [PATCH 19/59] fix edit dates for enum support --- JSONArray.java | 2 +- JSONObject.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 3aaa18563..b2717d9bd 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -76,7 +76,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-07-06 + * @version 2015-07-22 */ public class JSONArray implements Iterable { diff --git a/JSONObject.java b/JSONObject.java index fc7fb81e7..ed1159e9c 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-07-06 + * @version 2015-07-22 */ public class JSONObject { /** From b0191a6acf6024b6b3efbd48dba8826ca79b950d Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Wed, 29 Jul 2015 19:50:14 -0500 Subject: [PATCH 20/59] Update README --- README | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/README b/README index 925141f9e..dd5d1e6ac 100755 --- a/README +++ b/README @@ -1,16 +1,5 @@ JSON in Java [package org.json] -This package needs a new owner. I have not used it in over a decade, and I do -not have time to maintain programs that I do not use. - -If you think you can give this package a good home, please contact me. - -Douglas Crockford -douglas@crockford.com - -2015-02-06 - - JSON is a light-weight, language independent, data interchange format. See http://www.JSON.org/ From 0afd26623c0fa44c3c36d3b70323fa97c248106a Mon Sep 17 00:00:00 2001 From: Lukas Treyer Date: Sun, 4 Oct 2015 23:17:30 +0200 Subject: [PATCH 21/59] JSONObject and JSONArray initialization: JSONObject(Map map) allows to initialize the JSONObject with a Map JSONArray(Collection collection) allows to initialize a JSONArray with a Collection --- JSONArray.java | 4 ++-- JSONObject.java | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index b2717d9bd..36054113e 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -151,10 +151,10 @@ public JSONArray(String source) throws JSONException { * @param collection * A Collection. */ - public JSONArray(Collection collection) { + public JSONArray(Collection collection) { this.myArrayList = new ArrayList(); if (collection != null) { - Iterator iter = collection.iterator(); + Iterator iter = collection.iterator(); while (iter.hasNext()) { this.myArrayList.add(JSONObject.wrap(iter.next())); } diff --git a/JSONObject.java b/JSONObject.java index ed1159e9c..5d17cc7b9 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -243,12 +243,14 @@ public JSONObject(JSONTokener x) throws JSONException { * the JSONObject. * @throws JSONException */ - public JSONObject(Map map) { + public JSONObject(Map map) { this.map = new HashMap(); if (map != null) { - Iterator> i = map.entrySet().iterator(); + Set eSet = map.entrySet(); + @SuppressWarnings("unchecked") + Iterator> i = (Iterator>) eSet.iterator(); while (i.hasNext()) { - Entry entry = i.next(); + Entry entry = i.next(); Object value = entry.getValue(); if (value != null) { this.map.put(entry.getKey(), wrap(value)); From 409eb9f2922dcdc35013ebbbbfd3e3b05ea79259 Mon Sep 17 00:00:00 2001 From: Lukas Treyer Date: Sun, 11 Oct 2015 11:20:08 +0200 Subject: [PATCH 22/59] changed all method signatures containing collections and maps to accept wildcard generic types, e.g. Collection instead of Collection. This was proposed by other pull requests (#111, #112) already. Consider this commit as merge with #111 and #112. JSONArray: - put(Collection value) {...} - put(Map value) {...} - put(int index, Collection value) throws JSONException {...} - put(int index, Map value) throws JSONException {...} JSONObject: - put(String key, Collection value) throws JSONException {...} - put(String key, Map value) throws JSONException {...} Changed all code affected by new JSONObject and JSONArray constructors: JSONObject: - valueToString(Object value) throws JSONException { - value instanceof Map - value instanceof Collection } - wrap(Object object) { - value instanceof Map - value instanceof Collection } - writeValue(Writer writer, Object value, int indentFactor, int indent){ - value instanceof Map - value instanceof Collection } --- JSONArray.java | 8 ++++---- JSONObject.java | 19 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 36054113e..077eded4e 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -746,7 +746,7 @@ public JSONArray put(boolean value) { * A Collection value. * @return this. */ - public JSONArray put(Collection value) { + public JSONArray put(Collection value) { this.put(new JSONArray(value)); return this; } @@ -799,7 +799,7 @@ public JSONArray put(long value) { * A Map value. * @return this. */ - public JSONArray put(Map value) { + public JSONArray put(Map value) { this.put(new JSONObject(value)); return this; } @@ -848,7 +848,7 @@ public JSONArray put(int index, boolean value) throws JSONException { * @throws JSONException * If the index is negative or if the value is not finite. */ - public JSONArray put(int index, Collection value) throws JSONException { + public JSONArray put(int index, Collection value) throws JSONException { this.put(index, new JSONArray(value)); return this; } @@ -920,7 +920,7 @@ public JSONArray put(int index, long value) throws JSONException { * If the index is negative or if the the value is an invalid * number. */ - public JSONArray put(int index, Map value) throws JSONException { + public JSONArray put(int index, Map value) throws JSONException { this.put(index, new JSONObject(value)); return this; } diff --git a/JSONObject.java b/JSONObject.java index 5d17cc7b9..73c51f744 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -1206,7 +1206,7 @@ public JSONObject put(String key, boolean value) throws JSONException { * @return this. * @throws JSONException */ - public JSONObject put(String key, Collection value) throws JSONException { + public JSONObject put(String key, Collection value) throws JSONException { this.put(key, new JSONArray(value)); return this; } @@ -1270,7 +1270,7 @@ public JSONObject put(String key, long value) throws JSONException { * @return this. * @throws JSONException */ - public JSONObject put(String key, Map value) throws JSONException { + public JSONObject put(String key, Map value) throws JSONException { this.put(key, new JSONObject(value)); return this; } @@ -1666,12 +1666,12 @@ public static String valueToString(Object value) throws JSONException { } if (value instanceof Map) { @SuppressWarnings("unchecked") - Map map = (Map) value; + Map map = (Map) value; return new JSONObject(map).toString(); } if (value instanceof Collection) { @SuppressWarnings("unchecked") - Collection coll = (Collection) value; + Collection coll = (Collection) value; return new JSONArray(coll).toString(); } if (value.getClass().isArray()) { @@ -1710,7 +1710,7 @@ public static Object wrap(Object object) { if (object instanceof Collection) { @SuppressWarnings("unchecked") - Collection coll = (Collection) object; + Collection coll = (Collection) object; return new JSONArray(coll); } if (object.getClass().isArray()) { @@ -1718,7 +1718,7 @@ public static Object wrap(Object object) { } if (object instanceof Map) { @SuppressWarnings("unchecked") - Map map = (Map) object; + Map map = (Map) object; return new JSONObject(map); } Package objectPackage = object.getClass().getPackage(); @@ -1758,13 +1758,12 @@ static final Writer writeValue(Writer writer, Object value, ((JSONArray) value).write(writer, indentFactor, indent); } else if (value instanceof Map) { @SuppressWarnings("unchecked") - Map map = (Map) value; + Map map = (Map) value; new JSONObject(map).write(writer, indentFactor, indent); } else if (value instanceof Collection) { @SuppressWarnings("unchecked") - Collection coll = (Collection) value; - new JSONArray(coll).write(writer, indentFactor, - indent); + Collection coll = (Collection) value; + new JSONArray(coll).write(writer, indentFactor, indent); } else if (value.getClass().isArray()) { new JSONArray(value).write(writer, indentFactor, indent); } else if (value instanceof Number) { From 25b5aa7ef265c7a6335f9b6de32056d3a7d63447 Mon Sep 17 00:00:00 2001 From: Lukas Treyer Date: Sun, 11 Oct 2015 12:21:12 +0200 Subject: [PATCH 23/59] changed Map method parameters to Map changed Iterator to foreach loop in JSONArray ctor JSONArray(Collection collection) and JSONObject ctor JSONObject(Map map) --- JSONArray.java | 11 +++++------ JSONObject.java | 20 ++++++++------------ 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 077eded4e..d853b1a26 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -154,10 +154,9 @@ public JSONArray(String source) throws JSONException { public JSONArray(Collection collection) { this.myArrayList = new ArrayList(); if (collection != null) { - Iterator iter = collection.iterator(); - while (iter.hasNext()) { - this.myArrayList.add(JSONObject.wrap(iter.next())); - } + for (Object o: collection){ + this.myArrayList.add(JSONObject.wrap(o)); + } } } @@ -799,7 +798,7 @@ public JSONArray put(long value) { * A Map value. * @return this. */ - public JSONArray put(Map value) { + public JSONArray put(Map value) { this.put(new JSONObject(value)); return this; } @@ -920,7 +919,7 @@ public JSONArray put(int index, long value) throws JSONException { * If the index is negative or if the the value is an invalid * number. */ - public JSONArray put(int index, Map value) throws JSONException { + public JSONArray put(int index, Map value) throws JSONException { this.put(index, new JSONObject(value)); return this; } diff --git a/JSONObject.java b/JSONObject.java index 73c51f744..6d0d37b50 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -243,17 +243,13 @@ public JSONObject(JSONTokener x) throws JSONException { * the JSONObject. * @throws JSONException */ - public JSONObject(Map map) { + public JSONObject(Map map) { this.map = new HashMap(); if (map != null) { - Set eSet = map.entrySet(); - @SuppressWarnings("unchecked") - Iterator> i = (Iterator>) eSet.iterator(); - while (i.hasNext()) { - Entry entry = i.next(); - Object value = entry.getValue(); + for (final Entry e : map.entrySet()) { + final Object value = e.getValue(); if (value != null) { - this.map.put(entry.getKey(), wrap(value)); + this.map.put(String.valueOf(e.getKey()), wrap(value)); } } } @@ -1270,7 +1266,7 @@ public JSONObject put(String key, long value) throws JSONException { * @return this. * @throws JSONException */ - public JSONObject put(String key, Map value) throws JSONException { + public JSONObject put(String key, Map value) throws JSONException { this.put(key, new JSONObject(value)); return this; } @@ -1666,7 +1662,7 @@ public static String valueToString(Object value) throws JSONException { } if (value instanceof Map) { @SuppressWarnings("unchecked") - Map map = (Map) value; + Map map = (Map) value; return new JSONObject(map).toString(); } if (value instanceof Collection) { @@ -1718,7 +1714,7 @@ public static Object wrap(Object object) { } if (object instanceof Map) { @SuppressWarnings("unchecked") - Map map = (Map) object; + Map map = (Map) object; return new JSONObject(map); } Package objectPackage = object.getClass().getPackage(); @@ -1758,7 +1754,7 @@ static final Writer writeValue(Writer writer, Object value, ((JSONArray) value).write(writer, indentFactor, indent); } else if (value instanceof Map) { @SuppressWarnings("unchecked") - Map map = (Map) value; + Map map = (Map) value; new JSONObject(map).write(writer, indentFactor, indent); } else if (value instanceof Collection) { @SuppressWarnings("unchecked") From 4e77383472c055b08c919356fed276e2d78cceb3 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 12 Oct 2015 12:11:30 -0400 Subject: [PATCH 24/59] Properly overrides the Exception class. --- JSONException.java | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/JSONException.java b/JSONException.java index 6fef51943..41e85ae55 100755 --- a/JSONException.java +++ b/JSONException.java @@ -8,7 +8,6 @@ */ public class JSONException extends RuntimeException { private static final long serialVersionUID = 0; - private Throwable cause; /** * Constructs a JSONException with an explanatory message. @@ -16,28 +15,18 @@ public class JSONException extends RuntimeException { * @param message * Detail about the reason for the exception. */ - public JSONException(String message) { - super(message); + public JSONException(final String message) { + super(message); } /** * Constructs a new JSONException with the specified cause. - * @param cause The cause. + * + * @param cause + * The cause. */ - public JSONException(Throwable cause) { - super(cause.getMessage()); - this.cause = cause; + public JSONException(final Throwable cause) { + super(cause.getMessage(), cause); } - /** - * Returns the cause of this exception or null if the cause is nonexistent - * or unknown. - * - * @return the cause of this exception or null if the cause is nonexistent - * or unknown. - */ - @Override - public Throwable getCause() { - return this.cause; - } } From ceba8e8c3dee59191330ca4c912c0512452ebfde Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 12 Oct 2015 13:41:15 -0400 Subject: [PATCH 25/59] Fixes possible NPE --- XML.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/XML.java b/XML.java index 07090abe3..dcf0d741e 100755 --- a/XML.java +++ b/XML.java @@ -468,10 +468,12 @@ public static String toString(Object object, String tagName) // XML does not have good support for arrays. If an array appears in a place // where XML is lacking, synthesize an element. - } else { + } + if(object!=null){ if (object.getClass().isArray()) { object = new JSONArray(object); } + if (object instanceof JSONArray) { ja = (JSONArray)object; length = ja.length(); @@ -479,12 +481,12 @@ public static String toString(Object object, String tagName) sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName)); } return sb.toString(); - } else { - string = (object == null) ? "null" : escape(object.toString()); - return (tagName == null) ? "\"" + string + "\"" : - (string.length() == 0) ? "<" + tagName + "/>" : - "<" + tagName + ">" + string + ""; } } + string = (object == null) ? "null" : escape(object.toString()); + return (tagName == null) ? "\"" + string + "\"" : + (string.length() == 0) ? "<" + tagName + "/>" : + "<" + tagName + ">" + string + ""; + } } From e239e1967ac8230cd23ea7906c6d6b90f489d601 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 12 Oct 2015 14:52:17 -0400 Subject: [PATCH 26/59] Allows a custom message to be passed with a cause. --- JSONException.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/JSONException.java b/JSONException.java index 41e85ae55..086bac83f 100755 --- a/JSONException.java +++ b/JSONException.java @@ -7,6 +7,7 @@ * @version 2014-05-03 */ public class JSONException extends RuntimeException { + /** Serialization ID */ private static final long serialVersionUID = 0; /** @@ -19,6 +20,16 @@ public JSONException(final String message) { super(message); } + /** + * @param message + * Detail about the reason for the exception. + * @param cause + * The cause. + */ + public JSONException(String message, Throwable cause) { + super(message, cause); + } + /** * Constructs a new JSONException with the specified cause. * From 0e132415289c0306d028a5df560c75a0ee975493 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 12 Oct 2015 14:53:03 -0400 Subject: [PATCH 27/59] Expands javadoc --- JSONException.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/JSONException.java b/JSONException.java index 086bac83f..9ac810b2e 100755 --- a/JSONException.java +++ b/JSONException.java @@ -21,6 +21,8 @@ public JSONException(final String message) { } /** + * Constructs a JSONException with an explanatory message and cause. + * * @param message * Detail about the reason for the exception. * @param cause From 1b06a802cf134bd781d2bf3f4ce4e01bff92a612 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 12 Oct 2015 14:54:30 -0400 Subject: [PATCH 28/59] makes params final --- JSONException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONException.java b/JSONException.java index 9ac810b2e..2463d9683 100755 --- a/JSONException.java +++ b/JSONException.java @@ -28,7 +28,7 @@ public JSONException(final String message) { * @param cause * The cause. */ - public JSONException(String message, Throwable cause) { + public JSONException(final String message, final Throwable cause) { super(message, cause); } From 5ddc515679feb438e67c6fff8540f2e96a6843dc Mon Sep 17 00:00:00 2001 From: Lukas Treyer Date: Mon, 12 Oct 2015 23:52:14 +0200 Subject: [PATCH 29/59] removed 6 unnecessary @SuppressWarnings("unchecked") annotations. --- JSONObject.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/JSONObject.java b/JSONObject.java index 6d0d37b50..0e8ff0939 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -1661,12 +1661,10 @@ public static String valueToString(Object value) throws JSONException { return value.toString(); } if (value instanceof Map) { - @SuppressWarnings("unchecked") Map map = (Map) value; return new JSONObject(map).toString(); } if (value instanceof Collection) { - @SuppressWarnings("unchecked") Collection coll = (Collection) value; return new JSONArray(coll).toString(); } @@ -1705,7 +1703,6 @@ public static Object wrap(Object object) { } if (object instanceof Collection) { - @SuppressWarnings("unchecked") Collection coll = (Collection) object; return new JSONArray(coll); } @@ -1713,7 +1710,6 @@ public static Object wrap(Object object) { return new JSONArray(object); } if (object instanceof Map) { - @SuppressWarnings("unchecked") Map map = (Map) object; return new JSONObject(map); } @@ -1753,11 +1749,9 @@ static final Writer writeValue(Writer writer, Object value, } else if (value instanceof JSONArray) { ((JSONArray) value).write(writer, indentFactor, indent); } else if (value instanceof Map) { - @SuppressWarnings("unchecked") Map map = (Map) value; new JSONObject(map).write(writer, indentFactor, indent); } else if (value instanceof Collection) { - @SuppressWarnings("unchecked") Collection coll = (Collection) value; new JSONArray(coll).write(writer, indentFactor, indent); } else if (value.getClass().isArray()) { From 1448163981d7d81aacae15ddb2ff164947def02d Mon Sep 17 00:00:00 2001 From: John Aylward Date: Wed, 14 Oct 2015 00:41:38 -0400 Subject: [PATCH 30/59] fixes file date --- JSONException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONException.java b/JSONException.java index 2463d9683..8503e3554 100755 --- a/JSONException.java +++ b/JSONException.java @@ -4,7 +4,7 @@ * The JSONException is thrown by the JSON.org classes when things are amiss. * * @author JSON.org - * @version 2014-05-03 + * @version 2015-10-14 */ public class JSONException extends RuntimeException { /** Serialization ID */ From 637c1fe2b952699f68e502aec4f860e36543abf0 Mon Sep 17 00:00:00 2001 From: John Aylward Date: Wed, 14 Oct 2015 00:48:01 -0400 Subject: [PATCH 31/59] updates file dates --- XML.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/XML.java b/XML.java index dcf0d741e..02cc6c963 100755 --- a/XML.java +++ b/XML.java @@ -1,7 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org +Copyright (c) 2015 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 @@ -30,7 +30,7 @@ of this software and associated documentation files (the "Software"), to deal * This provides static methods to convert an XML text into a JSONObject, * and to covert a JSONObject into an XML text. * @author JSON.org - * @version 2014-05-03 + * @version 2015-10-14 */ public class XML { From 6757e04c0a8c0b1e6632a130f2b62b572b97e78e Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sun, 18 Oct 2015 10:23:43 -0500 Subject: [PATCH 32/59] Fix NullPointerException in XML.toString(object, tagName) Setting version date to match commit date. --- XML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XML.java b/XML.java index 02cc6c963..23a991906 100755 --- a/XML.java +++ b/XML.java @@ -30,7 +30,7 @@ of this software and associated documentation files (the "Software"), to deal * This provides static methods to convert an XML text into a JSONObject, * and to covert a JSONObject into an XML text. * @author JSON.org - * @version 2015-10-14 + * @version 2015-10-18 */ public class XML { From e7f4eb5f67048642e24634db8ec8c7e6f29c0c22 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sun, 18 Oct 2015 11:05:29 -0500 Subject: [PATCH 33/59] Set version date to match commit date, convert tabs to spaces. --- JSONException.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/JSONException.java b/JSONException.java index 8503e3554..7601b7e19 100755 --- a/JSONException.java +++ b/JSONException.java @@ -4,7 +4,7 @@ * The JSONException is thrown by the JSON.org classes when things are amiss. * * @author JSON.org - * @version 2015-10-14 + * @version 2015-10-18 */ public class JSONException extends RuntimeException { /** Serialization ID */ @@ -17,7 +17,7 @@ public class JSONException extends RuntimeException { * Detail about the reason for the exception. */ public JSONException(final String message) { - super(message); + super(message); } /** @@ -29,7 +29,7 @@ public JSONException(final String message) { * The cause. */ public JSONException(final String message, final Throwable cause) { - super(message, cause); + super(message, cause); } /** @@ -39,7 +39,7 @@ public JSONException(final String message, final Throwable cause) { * The cause. */ public JSONException(final Throwable cause) { - super(cause.getMessage(), cause); + super(cause.getMessage(), cause); } } From a07d391eaeaa974c0f47754b3e5eec5bbe921cf5 Mon Sep 17 00:00:00 2001 From: stleary Date: Sun, 25 Oct 2015 11:05:16 -0500 Subject: [PATCH 34/59] Include latest Maven release information --- README | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README b/README index dd5d1e6ac..bf7050e2a 100755 --- a/README +++ b/README @@ -62,3 +62,10 @@ 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 + +Release history: + +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 From 91c6f09be82b81f5a6d553f83b711d4cdba42ec5 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 26 Oct 2015 18:17:37 -0400 Subject: [PATCH 35/59] Modifies XML output to be handled the same for a native java array as well as a JSONArray. --- XML.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/XML.java b/XML.java index 23a991906..a55223c22 100755 --- a/XML.java +++ b/XML.java @@ -406,8 +406,11 @@ public static String toString(Object object, String tagName) 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 From 7886c96204c93c7cd4e9a9258b1bd40773fe11e9 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 26 Oct 2015 18:30:41 -0400 Subject: [PATCH 36/59] Changes JSONArray for loops to use the new iterators. --- XML.java | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/XML.java b/XML.java index a55223c22..bad8737b2 100755 --- a/XML.java +++ b/XML.java @@ -379,14 +379,13 @@ public static String toString(Object object) throws JSONException { public static String toString(Object object, String tagName) throws JSONException { StringBuilder sb = new StringBuilder(); - int i; JSONArray ja; JSONObject jo; String key; Iterator keys; - int length; String string; Object value; + if (object instanceof JSONObject) { // Emit @@ -417,12 +416,13 @@ public static String toString(Object object, String tagName) if ("content".equals(key)) { if (value instanceof JSONArray) { ja = (JSONArray)value; - length = ja.length(); - for (i = 0; i < length; i += 1) { + int i = 0; + for (Object val : ja) { if (i > 0) { sb.append('\n'); } - sb.append(escape(ja.get(i).toString())); + sb.append(escape(val.toString())); + i++; } } else { sb.append(escape(value.toString())); @@ -432,19 +432,17 @@ public static String toString(Object object, String tagName) } else if (value instanceof JSONArray) { ja = (JSONArray)value; - length = ja.length(); - for (i = 0; i < length; i += 1) { - value = ja.get(i); - if (value instanceof JSONArray) { + for (Object val : ja) { + if (val instanceof JSONArray) { sb.append('<'); sb.append(key); sb.append('>'); - sb.append(toString(value)); + sb.append(toString(val)); sb.append("'); } else { - sb.append(toString(value, key)); + sb.append(toString(val, key)); } } } else if ("".equals(value)) { @@ -479,9 +477,8 @@ public static String toString(Object object, String tagName) if (object instanceof JSONArray) { ja = (JSONArray)object; - length = ja.length(); - for (i = 0; i < length; i += 1) { - sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName)); + for (Object val : ja) { + sb.append(toString(val, tagName == null ? "array" : tagName)); } return sb.toString(); } From 105426b53f7f4f74fefa26e4d1321b633cc19628 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Mon, 26 Oct 2015 18:35:40 -0400 Subject: [PATCH 37/59] Formatting --- XML.java | 230 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 119 insertions(+), 111 deletions(-) diff --git a/XML.java b/XML.java index bad8737b2..dee75443d 100755 --- a/XML.java +++ b/XML.java @@ -27,49 +27,54 @@ of this software and associated documentation files (the "Software"), to deal import java.util.Iterator; /** - * This provides static methods to convert an XML text into a JSONObject, - * and to covert a JSONObject into an XML text. + * This provides static methods to convert an XML text into a JSONObject, and to + * covert a JSONObject into an XML text. + * * @author JSON.org * @version 2015-10-18 */ +@SuppressWarnings("boxing") public class XML { /** The Character '&'. */ - public static final Character AMP = '&'; + public static final Character AMP = '&'; /** The Character '''. */ - public static final Character APOS = '\''; + public static final Character APOS = '\''; /** The Character '!'. */ - public static final Character BANG = '!'; + public static final Character BANG = '!'; /** The Character '='. */ - public static final Character EQ = '='; + public static final Character EQ = '='; /** The Character '>'. */ - public static final Character GT = '>'; + public static final Character GT = '>'; /** The Character '<'. */ - public static final Character LT = '<'; + public static final Character LT = '<'; /** The Character '?'. */ public static final Character QUEST = '?'; /** The Character '"'. */ - public static final Character QUOT = '"'; + public static final Character QUOT = '"'; /** The Character '/'. */ public static final Character SLASH = '/'; /** * Replace special characters with XML escapes: + * *
      * & (ampersand) is replaced by &amp;
      * < (less than) is replaced by &lt;
      * > (greater than) is replaced by &gt;
      * " (double quote) is replaced by &quot;
      * 
- * @param string The string to be escaped. + * + * @param string + * The string to be escaped. * @return The escaped string. */ public static String escape(String string) { @@ -100,9 +105,11 @@ public static String escape(String string) { } /** - * Throw an exception if the string contains whitespace. - * Whitespace is not allowed in tagNames and attributes. - * @param string A string. + * Throw an exception if the string contains whitespace. Whitespace is not + * allowed in tagNames and attributes. + * + * @param string + * A string. * @throws JSONException */ public static void noSpace(String string) throws JSONException { @@ -112,42 +119,46 @@ public static void noSpace(String string) throws JSONException { } for (i = 0; i < length; i += 1) { if (Character.isWhitespace(string.charAt(i))) { - throw new JSONException("'" + string + - "' contains a space character."); + throw new JSONException("'" + string + + "' contains a space character."); } } } /** * Scan the content following the named tag, attaching it to the context. - * @param x The XMLTokener containing the source string. - * @param context The JSONObject that will include the new material. - * @param name The tag name. + * + * @param x + * The XMLTokener containing the source string. + * @param context + * The JSONObject that will include the new material. + * @param name + * The tag name. * @return true if the close tag is processed. * @throws JSONException */ - private static boolean parse(XMLTokener x, JSONObject context, - String name) throws JSONException { - char c; - int i; + private static boolean parse(XMLTokener x, JSONObject context, String name) + throws JSONException { + char c; + int i; JSONObject jsonobject = null; - String string; - String tagName; - Object token; - -// Test for and skip past these forms: -// -// -// -// -// Report errors for these forms: -// <> -// <= -// << + String string; + String tagName; + Object token; + + // Test for and skip past these forms: + // + // + // + // + // Report errors for these forms: + // <> + // <= + // << token = x.nextToken(); -// "); return false; } else if (token == SLASH) { -// Close tag } else if (token == SLASH) { + // Empty tag <.../> if (x.nextToken() != GT) { throw x.syntaxError("Misshaped tag"); } @@ -248,9 +257,8 @@ private static boolean parse(XMLTokener x, JSONObject context, } return false; -// Content, between <...> and - } else if (token == GT) { + // Content, between <...> and for (;;) { token = x.nextContent(); if (token == null) { @@ -259,20 +267,19 @@ private static boolean parse(XMLTokener x, JSONObject context, } return false; } else if (token instanceof String) { - string = (String)token; + string = (String) token; if (string.length() > 0) { jsonobject.accumulate("content", XML.stringToValue(string)); } -// Nested element - } else if (token == LT) { + // Nested element if (parse(x, jsonobject, tagName)) { if (jsonobject.length() == 0) { context.accumulate(tagName, ""); - } else if (jsonobject.length() == 1 && - jsonobject.opt("content") != null) { + } else if (jsonobject.length() == 1 + && jsonobject.opt("content") != null) { context.accumulate(tagName, jsonobject.opt("content")); } else { @@ -289,14 +296,15 @@ private static boolean parse(XMLTokener x, JSONObject context, } } - /** * Try to convert a string into a number, boolean, or null. If the string * can't be converted, return the string. This is much less ambitious than * JSONObject.stringToValue, especially because it does not attempt to * convert plus forms, octal forms, hex forms, or E forms lacking decimal * points. - * @param string A String. + * + * @param string + * A String. * @return A simple JSON value. */ public static Object stringToValue(String string) { @@ -310,9 +318,8 @@ public static Object stringToValue(String string) { return JSONObject.NULL; } -// If it might be a number, try converting it, first as a Long, and then as a -// Double. If that doesn't work, return the string. - + // If it might be a number, try converting it, first as a Long, and then + // as a Double. If that doesn't work, return the string. try { char initial = string.charAt(0); if (initial == '-' || (initial >= '0' && initial <= '9')) { @@ -321,30 +328,31 @@ public static Object stringToValue(String string) { return value; } } - } catch (Exception ignore) { + } catch (Exception ignore) { try { Double value = new Double(string); if (value.toString().equals(string)) { return value; } - } catch (Exception ignoreAlso) { + } catch (Exception ignoreAlso) { } } return string; } - /** * 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 - * <[ [ ]]> are ignored. - * @param string The source string. + * 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 <[ [ ]]> + * are ignored. + * + * @param string + * The source string. * @return A JSONObject containing the structured data from the XML string. * @throws JSONException */ @@ -357,65 +365,64 @@ public static JSONObject toJSONObject(String string) throws JSONException { return jo; } - /** * Convert a JSONObject into a well-formed, element-normal XML string. - * @param object A JSONObject. - * @return A string. - * @throws JSONException + * + * @param object + * A JSONObject. + * @return A string. + * @throws JSONException */ public static String toString(Object object) throws JSONException { return toString(object, null); } - /** * 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 object + * A JSONObject. + * @param tagName + * The optional name of the enclosing tag. * @return A string. * @throws JSONException */ public static String toString(Object object, String tagName) throws JSONException { - StringBuilder sb = new StringBuilder(); - JSONArray ja; - JSONObject jo; - String key; - Iterator keys; - String string; - Object value; - - if (object instanceof JSONObject) { + StringBuilder sb = new StringBuilder(); + JSONArray ja; + JSONObject jo; + String key; + Iterator keys; + String string; + Object value; -// Emit + if (object instanceof JSONObject) { + // Emit if (tagName != null) { sb.append('<'); sb.append(tagName); sb.append('>'); } -// Loop thru the keys. - - jo = (JSONObject)object; + // Loop thru the keys. + jo = (JSONObject) object; keys = jo.keys(); while (keys.hasNext()) { key = keys.next(); value = jo.opt(key); if (value == null) { value = ""; - }else if(value.getClass().isArray()){ + } else if (value.getClass().isArray()) { value = new JSONArray(value); } - string = value instanceof String ? (String)value : null; - - -// Emit content in body + string = value instanceof String ? (String) value : null; + // Emit content in body if ("content".equals(key)) { if (value instanceof JSONArray) { - ja = (JSONArray)value; + ja = (JSONArray) value; int i = 0; for (Object val : ja) { if (i > 0) { @@ -428,10 +435,10 @@ public static String toString(Object object, String tagName) sb.append(escape(value.toString())); } -// Emit an array of similar keys + // Emit an array of similar keys } else if (value instanceof JSONArray) { - ja = (JSONArray)value; + ja = (JSONArray) value; for (Object val : ja) { if (val instanceof JSONArray) { sb.append('<'); @@ -450,7 +457,7 @@ public static String toString(Object object, String tagName) sb.append(key); sb.append("/>"); -// Emit a new tag + // Emit a new tag } else { sb.append(toString(value, key)); @@ -458,35 +465,36 @@ public static String toString(Object object, String tagName) } if (tagName != null) { -// Emit the close tag - + // Emit the close tag sb.append("'); } return sb.toString(); -// XML does not have good support for arrays. If an array appears in a place -// where XML is lacking, synthesize an element. - } - if(object!=null){ + + if (object != null) { if (object.getClass().isArray()) { object = new JSONArray(object); } - + if (object instanceof JSONArray) { - ja = (JSONArray)object; + ja = (JSONArray) object; for (Object val : ja) { + // XML does not have good support for arrays. If an array + // appears in a place where XML is lacking, synthesize an + // element. sb.append(toString(val, tagName == null ? "array" : tagName)); } return sb.toString(); } } + string = (object == null) ? "null" : escape(object.toString()); - return (tagName == null) ? "\"" + string + "\"" : - (string.length() == 0) ? "<" + tagName + "/>" : - "<" + tagName + ">" + string + ""; - + return (tagName == null) ? "\"" + string + "\"" + : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName + + ">" + string + ""; + } } From 33ae025e7864d8392c76f4332821d0a2b1f9f4dd Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Thu, 29 Oct 2015 18:24:46 -0500 Subject: [PATCH 38/59] Update JSONObject.java Update version for https://github.com/douglascrockford/JSON-java/pull/153 --- JSONObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONObject.java b/JSONObject.java index 0e8ff0939..a23daab7d 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-07-22 + * @version 2015-10-29 */ public class JSONObject { /** From a109f581c885b24d19d8e8e659a1d68af61605ce Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Thu, 29 Oct 2015 18:25:27 -0500 Subject: [PATCH 39/59] Update JSONArray.java Update version for https://github.com/douglascrockford/JSON-java/pull/153 --- JSONArray.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONArray.java b/JSONArray.java index d853b1a26..5ccb65b79 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -76,7 +76,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-07-22 + * @version 2015-10-29 */ public class JSONArray implements Iterable { From 5f2e77f9ddf1c6a9f67ea239be1802719029ec15 Mon Sep 17 00:00:00 2001 From: stleary Date: Sat, 21 Nov 2015 11:50:31 -0600 Subject: [PATCH 40/59] Update readme with proposed release information --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index bf7050e2a..02d63ad3a 100755 --- a/README +++ b/README @@ -65,6 +65,9 @@ Unit tests are maintained in a separate project. Contributing developers can tes Release history: +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: From cadba9400c56848527c298f3c9f5cfad9c69ff4c Mon Sep 17 00:00:00 2001 From: Andrew Fletcher Date: Wed, 2 Dec 2015 10:49:54 -0800 Subject: [PATCH 41/59] Update JavaDoc for JSONObject Constructors Two JSONObject constructors incorrectly specify a @throws JSONException tag in the JavaDoc for those constructors. Remove the relevant JavaDoc. --- JSONObject.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/JSONObject.java b/JSONObject.java index a23daab7d..2ac21c9ae 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -165,10 +165,6 @@ public JSONObject() { * A JSONObject. * @param names * An array of strings. - * @throws JSONException - * @exception JSONException - * If a value is a non-finite number or if a name is - * duplicated. */ public JSONObject(JSONObject jo, String[] names) { this(); @@ -241,7 +237,6 @@ public JSONObject(JSONTokener x) throws JSONException { * @param map * A map object that can be used to initialize the contents of * the JSONObject. - * @throws JSONException */ public JSONObject(Map map) { this.map = new HashMap(); From 39e3ccc6715833488755c9938d1a1be8af1e2c8c Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 5 Dec 2015 20:14:15 -0600 Subject: [PATCH 42/59] Update version Update version after merge of https://github.com/douglascrockford/JSON-java/pull/179 --- JSONObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONObject.java b/JSONObject.java index 2ac21c9ae..53cdeec43 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-10-29 + * @version 2015-12-05 */ public class JSONObject { /** From 23cf659730620a64eb8424839729545a584d638f Mon Sep 17 00:00:00 2001 From: Siyuan Ren Date: Wed, 9 Dec 2015 01:50:59 +0000 Subject: [PATCH 43/59] Remove executable permission bit from file mode --- CDL.java | 2 +- Cookie.java | 2 +- CookieList.java | 2 +- HTTP.java | 2 +- HTTPTokener.java | 2 +- JSONException.java | 2 +- JSONML.java | 2 +- JSONObject.java | 2 +- JSONString.java | 0 JSONStringer.java | 2 +- JSONWriter.java | 2 +- README | 0 XML.java | 2 +- XMLTokener.java | 2 +- 14 files changed, 12 insertions(+), 12 deletions(-) mode change 100755 => 100644 CDL.java mode change 100755 => 100644 Cookie.java mode change 100755 => 100644 CookieList.java mode change 100755 => 100644 HTTP.java mode change 100755 => 100644 HTTPTokener.java mode change 100755 => 100644 JSONException.java mode change 100755 => 100644 JSONML.java mode change 100755 => 100644 JSONObject.java mode change 100755 => 100644 JSONString.java mode change 100755 => 100644 JSONStringer.java mode change 100755 => 100644 JSONWriter.java mode change 100755 => 100644 README mode change 100755 => 100644 XML.java mode change 100755 => 100644 XMLTokener.java diff --git a/CDL.java b/CDL.java old mode 100755 new mode 100644 index 8520e862d..aaa39cdda --- a/CDL.java +++ b/CDL.java @@ -41,7 +41,7 @@ of this software and associated documentation files (the "Software"), to deal * The names for the elements in the JSONObjects can be taken from the names * in the first row. * @author JSON.org - * @version 2015-05-01 + * @version 2015-12-09 */ public class CDL { diff --git a/Cookie.java b/Cookie.java old mode 100755 new mode 100644 index 1867dbd74..348dc688d --- a/Cookie.java +++ b/Cookie.java @@ -28,7 +28,7 @@ of this software and associated documentation files (the "Software"), to deal * Convert a web browser cookie specification to a JSONObject and back. * JSON and Cookies are both notations for name/value pairs. * @author JSON.org - * @version 2014-05-03 + * @version 2015-12-09 */ public class Cookie { diff --git a/CookieList.java b/CookieList.java old mode 100755 new mode 100644 index b716fd7e3..7a5628e91 --- a/CookieList.java +++ b/CookieList.java @@ -29,7 +29,7 @@ of this software and associated documentation files (the "Software"), to deal /** * Convert a web browser cookie list string to a JSONObject and back. * @author JSON.org - * @version 2014-05-03 + * @version 2015-12-09 */ public class CookieList { diff --git a/HTTP.java b/HTTP.java old mode 100755 new mode 100644 index 648f4dad7..b14d04ec9 --- a/HTTP.java +++ b/HTTP.java @@ -29,7 +29,7 @@ of this software and associated documentation files (the "Software"), to deal /** * Convert an HTTP header to a JSONObject and back. * @author JSON.org - * @version 2014-05-03 + * @version 2015-12-09 */ public class HTTP { diff --git a/HTTPTokener.java b/HTTPTokener.java old mode 100755 new mode 100644 index b2489b68d..55f48ffa5 --- a/HTTPTokener.java +++ b/HTTPTokener.java @@ -28,7 +28,7 @@ of this software and associated documentation files (the "Software"), to deal * The HTTPTokener extends the JSONTokener to provide additional methods * for the parsing of HTTP headers. * @author JSON.org - * @version 2014-05-03 + * @version 2015-12-09 */ public class HTTPTokener extends JSONTokener { diff --git a/JSONException.java b/JSONException.java old mode 100755 new mode 100644 index 7601b7e19..72542dfb6 --- a/JSONException.java +++ b/JSONException.java @@ -4,7 +4,7 @@ * The JSONException is thrown by the JSON.org classes when things are amiss. * * @author JSON.org - * @version 2015-10-18 + * @version 2015-12-09 */ public class JSONException extends RuntimeException { /** Serialization ID */ diff --git a/JSONML.java b/JSONML.java old mode 100755 new mode 100644 index 42027cb00..a4b874dd5 --- a/JSONML.java +++ b/JSONML.java @@ -33,7 +33,7 @@ of this software and associated documentation files (the "Software"), to deal * the JsonML transform. * * @author JSON.org - * @version 2014-05-03 + * @version 2015-12-09 */ public class JSONML { diff --git a/JSONObject.java b/JSONObject.java old mode 100755 new mode 100644 index 53cdeec43..e52a567f8 --- a/JSONObject.java +++ b/JSONObject.java @@ -92,7 +92,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-12-05 + * @version 2015-12-09 */ public class JSONObject { /** diff --git a/JSONString.java b/JSONString.java old mode 100755 new mode 100644 diff --git a/JSONStringer.java b/JSONStringer.java old mode 100755 new mode 100644 index 25c2e5d78..5fbc96a9a --- a/JSONStringer.java +++ b/JSONStringer.java @@ -54,7 +54,7 @@ of this software and associated documentation files (the "Software"), to deal *

* This can sometimes be easier than using a JSONObject to build a string. * @author JSON.org - * @version 2008-09-18 + * @version 2015-12-09 */ public class JSONStringer extends JSONWriter { /** diff --git a/JSONWriter.java b/JSONWriter.java old mode 100755 new mode 100644 index 07bbc8cfa..09d113030 --- a/JSONWriter.java +++ b/JSONWriter.java @@ -54,7 +54,7 @@ of this software and associated documentation files (the "Software"), to deal *

* This can sometimes be easier than using a JSONObject to build a string. * @author JSON.org - * @version 2011-11-24 + * @version 2015-12-09 */ public class JSONWriter { private static final int maxdepth = 200; diff --git a/README b/README old mode 100755 new mode 100644 diff --git a/XML.java b/XML.java old mode 100755 new mode 100644 index 23a991906..9b66a1caf --- a/XML.java +++ b/XML.java @@ -30,7 +30,7 @@ of this software and associated documentation files (the "Software"), to deal * This provides static methods to convert an XML text into a JSONObject, * and to covert a JSONObject into an XML text. * @author JSON.org - * @version 2015-10-18 + * @version 2015-12-09 */ public class XML { diff --git a/XMLTokener.java b/XMLTokener.java old mode 100755 new mode 100644 index d3197653c..e45e747dc --- a/XMLTokener.java +++ b/XMLTokener.java @@ -28,7 +28,7 @@ of this software and associated documentation files (the "Software"), to deal * The XMLTokener extends the JSONTokener to provide additional methods * for the parsing of XML texts. * @author JSON.org - * @version 2014-05-03 + * @version 2015-12-09 */ public class XMLTokener extends JSONTokener { From 8688494876025633f16951410365a58d2e38a1d3 Mon Sep 17 00:00:00 2001 From: stleary Date: Wed, 23 Dec 2015 19:53:30 -0600 Subject: [PATCH 44/59] change to public, write(writer, indentfactor, indent) --- JSONArray.java | 4 +++- JSONObject.java | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index 5ccb65b79..a3df9758a 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -1083,6 +1083,8 @@ public Writer write(Writer writer) throws JSONException { *

* Warning: This method assumes that the data structure is acyclical. * + * @param writer + * Writes the serialized JSON * @param indentFactor * The number of spaces to add to each level of indentation. * @param indent @@ -1090,7 +1092,7 @@ public Writer write(Writer writer) throws JSONException { * @return The writer. * @throws JSONException */ - Writer write(Writer writer, int indentFactor, int indent) + public Writer write(Writer writer, int indentFactor, int indent) throws JSONException { try { boolean commanate = false; diff --git a/JSONObject.java b/JSONObject.java index e52a567f8..2f613f855 100644 --- a/JSONObject.java +++ b/JSONObject.java @@ -1781,10 +1781,16 @@ static final void indent(Writer writer, int indent) throws IOException { *

* Warning: This method assumes that the data structure is acyclical. * + * @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. * @return The writer. * @throws JSONException */ - Writer write(Writer writer, int indentFactor, int indent) + public Writer write(Writer writer, int indentFactor, int indent) throws JSONException { try { boolean commanate = false; From a971736f5bb420380003ba2f81cff78081b11e67 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Fri, 1 Jan 2016 13:52:12 -0600 Subject: [PATCH 45/59] Update version string for https://github.com/douglascrockford/JSON-java/pull/170 --- XML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XML.java b/XML.java index 8fb6c2bd8..f14463c94 100644 --- a/XML.java +++ b/XML.java @@ -31,7 +31,7 @@ of this software and associated documentation files (the "Software"), to deal * covert a JSONObject into an XML text. * * @author JSON.org - * @version 2015-12-09 + * @version 2016-01-01 */ @SuppressWarnings("boxing") public class XML { From e2a0bb16a2e23e6a1f9fc822f07492f41fe1ecec Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Fri, 1 Jan 2016 14:11:02 -0600 Subject: [PATCH 46/59] Update README with number information See https://github.com/douglascrockford/JSON-java/issues/162 --- README | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README b/README index 02d63ad3a..9867f1bcb 100644 --- a/README +++ b/README @@ -63,6 +63,11 @@ 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/p +ublications/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 pr +ovided in the form of get(), opt(), and put() API methods. + Release history: 20151123 JSONObject and JSONArray initialization with generics. Contains the From 2b2fac3eb12fe09a96535cacbcc45a7539c9a1b5 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Fri, 1 Jan 2016 16:17:30 -0600 Subject: [PATCH 47/59] Broke up some overly long lines. --- README | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/README b/README index 9867f1bcb..4d6751c30 100644 --- a/README +++ b/README @@ -61,19 +61,26 @@ 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/p -ublications/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 pr -ovided in the form of get(), opt(), and put() API methods. +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. Release history: 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. +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: +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 From 07b2d65e30c4a7ffa789360c2f13e5eb5e417339 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 27 Jan 2016 10:39:31 -0500 Subject: [PATCH 48/59] Fixes #187 -0 now returns as a double. --- JSONObject.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/JSONObject.java b/JSONObject.java index 2f613f855..7b71f37b3 100644 --- a/JSONObject.java +++ b/JSONObject.java @@ -30,7 +30,8 @@ of this software and associated documentation files (the "Software"), to deal import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.math.*; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; @@ -1500,7 +1501,8 @@ public static Object stringToValue(String string) { if ((b >= '0' && b <= '9') || b == '-') { try { if (string.indexOf('.') > -1 || string.indexOf('e') > -1 - || string.indexOf('E') > -1) { + || string.indexOf('E') > -1 + || "0".equals(string.substring(1))) { d = Double.valueOf(string); if (!d.isInfinite() && !d.isNaN()) { return d; @@ -1508,11 +1510,10 @@ public static Object stringToValue(String string) { } else { Long myLong = new Long(string); if (string.equals(myLong.toString())) { - if (myLong == myLong.intValue()) { - return myLong.intValue(); - } else { - return myLong; + if (myLong.longValue() == myLong.intValue()) { + return Integer.valueOf(myLong.intValue()); } + return myLong; } } } catch (Exception ignore) { From 39b1c0cb6682310aef7f7579836eb9561e3ad275 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 27 Jan 2016 10:45:23 -0500 Subject: [PATCH 49/59] fixes error in -0 check --- JSONObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONObject.java b/JSONObject.java index 7b71f37b3..dc47cd2a2 100644 --- a/JSONObject.java +++ b/JSONObject.java @@ -1502,7 +1502,7 @@ public static Object stringToValue(String string) { try { if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1 - || "0".equals(string.substring(1))) { + || "-0".equals(string)) { d = Double.valueOf(string); if (!d.isInfinite() && !d.isNaN()) { return d; From 3007fc8ebe591b93caa9f6ab6b46e8677058a7a8 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 27 Jan 2016 15:03:19 -0500 Subject: [PATCH 50/59] Removes custom XML stringToValue method in favor of keeping a consistent implementation in JSONObject --- JSONML.java | 4 ++-- JSONObject.java | 7 +++---- XML.java | 48 ++---------------------------------------------- 3 files changed, 7 insertions(+), 52 deletions(-) diff --git a/JSONML.java b/JSONML.java index a4b874dd5..8d5e6c695 100644 --- a/JSONML.java +++ b/JSONML.java @@ -174,7 +174,7 @@ private static Object parse( if (!(token instanceof String)) { throw x.syntaxError("Missing value"); } - newjo.accumulate(attribute, XML.stringToValue((String)token)); + newjo.accumulate(attribute, JSONObject.stringToValue((String)token)); token = null; } else { newjo.accumulate(attribute, ""); @@ -227,7 +227,7 @@ private static Object parse( } else { if (ja != null) { ja.put(token instanceof String - ? XML.stringToValue((String)token) + ? JSONObject.stringToValue((String)token) : token); } } diff --git a/JSONObject.java b/JSONObject.java index dc47cd2a2..c37de6bea 100644 --- a/JSONObject.java +++ b/JSONObject.java @@ -1478,7 +1478,6 @@ public boolean similar(Object other) { * @return A simple JSON value. */ public static Object stringToValue(String string) { - Double d; if (string.equals("")) { return string; } @@ -1497,13 +1496,13 @@ public static Object stringToValue(String string) { * produced, then the value will just be a string. */ - char b = string.charAt(0); - if ((b >= '0' && b <= '9') || b == '-') { + char initial = string.charAt(0); + if ((initial >= '0' && initial <= '9') || initial == '-') { try { if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1 || "-0".equals(string)) { - d = Double.valueOf(string); + Double d = Double.valueOf(string); if (!d.isInfinite() && !d.isNaN()) { return d; } diff --git a/XML.java b/XML.java index f14463c94..c0e84f06b 100644 --- a/XML.java +++ b/XML.java @@ -238,7 +238,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name) throw x.syntaxError("Missing value"); } jsonobject.accumulate(string, - XML.stringToValue((String) token)); + JSONObject.stringToValue((String) token)); token = null; } else { jsonobject.accumulate(string, ""); @@ -270,7 +270,7 @@ private static boolean parse(XMLTokener x, JSONObject context, String name) string = (String) token; if (string.length() > 0) { jsonobject.accumulate("content", - XML.stringToValue(string)); + JSONObject.stringToValue(string)); } } else if (token == LT) { @@ -296,50 +296,6 @@ private static boolean parse(XMLTokener x, JSONObject context, String name) } } - /** - * Try to convert a string into a number, boolean, or null. If the string - * can't be converted, return the string. This is much less ambitious than - * JSONObject.stringToValue, especially because it does not attempt to - * convert plus forms, octal forms, hex forms, or E forms lacking decimal - * points. - * - * @param string - * A String. - * @return A simple JSON value. - */ - public static Object stringToValue(String string) { - if ("true".equalsIgnoreCase(string)) { - return Boolean.TRUE; - } - if ("false".equalsIgnoreCase(string)) { - return Boolean.FALSE; - } - if ("null".equalsIgnoreCase(string)) { - return JSONObject.NULL; - } - - // If it might be a number, try converting it, first as a Long, and then - // as a Double. If that doesn't work, return the string. - try { - char initial = string.charAt(0); - if (initial == '-' || (initial >= '0' && initial <= '9')) { - Long value = new Long(string); - if (value.toString().equals(string)) { - return value; - } - } - } catch (Exception ignore) { - try { - Double value = new Double(string); - if (value.toString().equals(string)) { - return value; - } - } catch (Exception ignoreAlso) { - } - } - return string; - } - /** * Convert a well-formed (but not necessarily valid) XML string into a * JSONObject. Some information may be lost in this transformation because From c2b3f2bdb164dc884efc5903ce807f7698f5dd94 Mon Sep 17 00:00:00 2001 From: "John J. Aylward" Date: Wed, 27 Jan 2016 15:21:11 -0500 Subject: [PATCH 51/59] adds back in the XML.stringToValue method, but deprecates it. --- XML.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/XML.java b/XML.java index c0e84f06b..a45ef156a 100644 --- a/XML.java +++ b/XML.java @@ -295,6 +295,18 @@ private static boolean parse(XMLTokener x, JSONObject context, String name) } } } + + /** + * This method has been deprecated in favor of the + * {@link JSONObject.stringToValue(String)} method. Use it instead. + * + * @deprecated Use {@link JSONObject#stringToValue(String)} instead. + * @param string + * @return JSON value of this string or the string + */ + public static Object stringToValue(String string) { + return JSONObject.stringToValue(string); + } /** * Convert a well-formed (but not necessarily valid) XML string into a From 62486fdea41f3aed606f2b69f4576b313077fad8 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 30 Jan 2016 15:44:08 -0600 Subject: [PATCH 52/59] Version date --- JSONML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONML.java b/JSONML.java index 8d5e6c695..9acf21da0 100644 --- a/JSONML.java +++ b/JSONML.java @@ -33,7 +33,7 @@ of this software and associated documentation files (the "Software"), to deal * the JsonML transform. * * @author JSON.org - * @version 2015-12-09 + * @version 2016-01-30 */ public class JSONML { From 93c79ca5668c7179e99c34a1cb750d6d7066c39c Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 30 Jan 2016 15:44:41 -0600 Subject: [PATCH 53/59] Version date --- JSONObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSONObject.java b/JSONObject.java index c37de6bea..27be3ec18 100644 --- a/JSONObject.java +++ b/JSONObject.java @@ -93,7 +93,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-12-09 + * @version 2015-01-30 */ public class JSONObject { /** From ba2585fe6c18eee9873d1e3a98c459f9e59dc02b Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 30 Jan 2016 15:45:11 -0600 Subject: [PATCH 54/59] Version date --- XML.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XML.java b/XML.java index a45ef156a..bbcda3b3b 100644 --- a/XML.java +++ b/XML.java @@ -31,7 +31,7 @@ of this software and associated documentation files (the "Software"), to deal * covert a JSONObject into an XML text. * * @author JSON.org - * @version 2016-01-01 + * @version 2016-01-30 */ @SuppressWarnings("boxing") public class XML { From 60349ece54204f7ee261b3e6fd2b058733dce388 Mon Sep 17 00:00:00 2001 From: skreutzer Date: Mon, 8 Feb 2016 23:30:27 -0500 Subject: [PATCH 55/59] Java 1.6 compatibility. --- JSONArray.java | 6 ++++-- JSONObject.java | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/JSONArray.java b/JSONArray.java index a3df9758a..f29085bdc 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -76,7 +76,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-10-29 + * @version 2016-02-08 */ public class JSONArray implements Iterable { @@ -593,7 +593,9 @@ public > E optEnum(Class clazz, int index, E defaultValue) return myE; } return Enum.valueOf(clazz, val.toString()); - } catch (IllegalArgumentException | NullPointerException e) { + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (NullPointerException e) { return defaultValue; } } diff --git a/JSONObject.java b/JSONObject.java index 27be3ec18..1ce25401f 100644 --- a/JSONObject.java +++ b/JSONObject.java @@ -93,7 +93,7 @@ of this software and associated documentation files (the "Software"), to deal * * * @author JSON.org - * @version 2015-01-30 + * @version 2016-02-08 */ public class JSONObject { /** @@ -901,7 +901,9 @@ public > E optEnum(Class clazz, String key, E defaultValue) return myE; } return Enum.valueOf(clazz, val.toString()); - } catch (IllegalArgumentException | NullPointerException e) { + } catch (IllegalArgumentException e) { + return defaultValue; + } catch (NullPointerException e) { return defaultValue; } } From 2657915293eca812160b9e8d8a143e181aab63d1 Mon Sep 17 00:00:00 2001 From: Sean Leary Date: Sat, 13 Feb 2016 22:26:45 -0600 Subject: [PATCH 56/59] Update README Include some text about 1.6 compatibility and add the latest release information. --- README | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README b/README index 4d6751c30..8ac6ccdc4 100644 --- a/README +++ b/README @@ -15,7 +15,7 @@ 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.8. +The package compiles on Java 1.6-1.8. JSONObject.java: The JSONObject can parse text from a String or a JSONTokener @@ -32,7 +32,6 @@ tokens. It can be constructed from a String, Reader, or InputStream. JSONException.java: The JSONException is the standard exception type thrown by this package. - JSONString.java: The JSONString interface requires a toJSONString method, allowing an object to provide its own serialization. @@ -73,8 +72,13 @@ This package fully supports Integer, Long, and Double Java types. Partial suppor 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. + Release history: +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. From b95ad85219673d3d3d30ae962e2190c3bdd39634 Mon Sep 17 00:00:00 2001 From: AmirHossein Date: Wed, 24 Feb 2016 18:02:14 +0330 Subject: [PATCH 57/59] initial --- CDL.java => org/json/CDL.java | 0 Cookie.java => org/json/Cookie.java | 0 CookieList.java => org/json/CookieList.java | 0 HTTP.java => org/json/HTTP.java | 326 ++++----- HTTPTokener.java => org/json/HTTPTokener.java | 0 JSONArray.java => org/json/JSONArray.java | 487 ++++++------- .../json/JSONException.java | 0 JSONML.java => org/json/JSONML.java | 0 JSONObject.java => org/json/JSONObject.java | 95 ++- JSONString.java => org/json/JSONString.java | 0 .../json/JSONStringer.java | 156 ++--- JSONTokener.java => org/json/JSONTokener.java | 7 +- JSONWriter.java => org/json/JSONWriter.java | 654 +++++++++--------- Property.java => org/json/Property.java | 0 README => org/json/README | 0 XML.java => org/json/XML.java | 0 XMLTokener.java => org/json/XMLTokener.java | 0 17 files changed, 874 insertions(+), 851 deletions(-) rename CDL.java => org/json/CDL.java (100%) rename Cookie.java => org/json/Cookie.java (100%) rename CookieList.java => org/json/CookieList.java (100%) rename HTTP.java => org/json/HTTP.java (97%) rename HTTPTokener.java => org/json/HTTPTokener.java (100%) rename JSONArray.java => org/json/JSONArray.java (71%) rename JSONException.java => org/json/JSONException.java (100%) rename JSONML.java => org/json/JSONML.java (100%) rename JSONObject.java => org/json/JSONObject.java (95%) rename JSONString.java => org/json/JSONString.java (100%) rename JSONStringer.java => org/json/JSONStringer.java (97%) rename JSONTokener.java => org/json/JSONTokener.java (98%) rename JSONWriter.java => org/json/JSONWriter.java (96%) rename Property.java => org/json/Property.java (100%) rename README => org/json/README (100%) rename XML.java => org/json/XML.java (100%) rename XMLTokener.java => org/json/XMLTokener.java (100%) diff --git a/CDL.java b/org/json/CDL.java similarity index 100% rename from CDL.java rename to org/json/CDL.java diff --git a/Cookie.java b/org/json/Cookie.java similarity index 100% rename from Cookie.java rename to org/json/Cookie.java diff --git a/CookieList.java b/org/json/CookieList.java similarity index 100% rename from CookieList.java rename to org/json/CookieList.java diff --git a/HTTP.java b/org/json/HTTP.java similarity index 97% rename from HTTP.java rename to org/json/HTTP.java index b14d04ec9..c3d8b7827 100644 --- a/HTTP.java +++ b/org/json/HTTP.java @@ -1,163 +1,163 @@ -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. -*/ - -import java.util.Iterator; - -/** - * Convert an HTTP header to a JSONObject and back. - * @author JSON.org - * @version 2015-12-09 - */ -public class HTTP { - - /** Carriage return/line feed. */ - public static final String CRLF = "\r\n"; - - /** - * Convert an HTTP header string into a JSONObject. It can be a request - * header or a response header. A request header will contain - *
{
-     *    Method: "POST" (for example),
-     *    "Request-URI": "/" (for example),
-     *    "HTTP-Version": "HTTP/1.1" (for example)
-     * }
- * A response header will contain - *
{
-     *    "HTTP-Version": "HTTP/1.1" (for example),
-     *    "Status-Code": "200" (for example),
-     *    "Reason-Phrase": "OK" (for example)
-     * }
- * In addition, the other parameters in the header will be captured, using - * the HTTP field names as JSON names, so that
-     *    Date: Sun, 26 May 2002 18:06:04 GMT
-     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
-     *    Cache-Control: no-cache
- * become - *
{...
-     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
-     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
-     *    "Cache-Control": "no-cache",
-     * ...}
- * It does no further checking or conversion. It does not parse dates. - * It does not do '%' transforms on URLs. - * @param string An HTTP header string. - * @return A JSONObject containing the elements and attributes - * of the XML string. - * @throws JSONException - */ - public static JSONObject toJSONObject(String string) throws JSONException { - JSONObject jo = new JSONObject(); - HTTPTokener x = new HTTPTokener(string); - String token; - - token = x.nextToken(); - if (token.toUpperCase().startsWith("HTTP")) { - -// Response - - jo.put("HTTP-Version", token); - jo.put("Status-Code", x.nextToken()); - jo.put("Reason-Phrase", x.nextTo('\0')); - x.next(); - - } else { - -// Request - - jo.put("Method", token); - jo.put("Request-URI", x.nextToken()); - jo.put("HTTP-Version", x.nextToken()); - } - -// Fields - - while (x.more()) { - String name = x.nextTo(':'); - x.next(':'); - jo.put(name, x.nextTo('\0')); - x.next(); - } - return jo; - } - - - /** - * Convert a JSONObject into an HTTP header. A request header must contain - *
{
-     *    Method: "POST" (for example),
-     *    "Request-URI": "/" (for example),
-     *    "HTTP-Version": "HTTP/1.1" (for example)
-     * }
- * A response header must contain - *
{
-     *    "HTTP-Version": "HTTP/1.1" (for example),
-     *    "Status-Code": "200" (for example),
-     *    "Reason-Phrase": "OK" (for example)
-     * }
- * Any other members of the JSONObject will be output as HTTP fields. - * The result will end with two CRLF pairs. - * @param jo A JSONObject - * @return An HTTP header string. - * @throws JSONException if the object does not contain enough - * information. - */ - public static String toString(JSONObject jo) throws JSONException { - Iterator keys = jo.keys(); - String string; - StringBuilder sb = new StringBuilder(); - if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { - sb.append(jo.getString("HTTP-Version")); - sb.append(' '); - sb.append(jo.getString("Status-Code")); - sb.append(' '); - sb.append(jo.getString("Reason-Phrase")); - } else if (jo.has("Method") && jo.has("Request-URI")) { - sb.append(jo.getString("Method")); - sb.append(' '); - sb.append('"'); - sb.append(jo.getString("Request-URI")); - sb.append('"'); - sb.append(' '); - sb.append(jo.getString("HTTP-Version")); - } else { - 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); - sb.append(": "); - sb.append(jo.getString(string)); - sb.append(CRLF); - } - } - sb.append(CRLF); - return sb.toString(); - } -} +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. +*/ + +import java.util.Iterator; + +/** + * Convert an HTTP header to a JSONObject and back. + * @author JSON.org + * @version 2015-12-09 + */ +public class HTTP { + + /** Carriage return/line feed. */ + public static final String CRLF = "\r\n"; + + /** + * Convert an HTTP header string into a JSONObject. It can be a request + * header or a response header. A request header will contain + *
{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }
+ * A response header will contain + *
{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }
+ * In addition, the other parameters in the header will be captured, using + * the HTTP field names as JSON names, so that
+     *    Date: Sun, 26 May 2002 18:06:04 GMT
+     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
+     *    Cache-Control: no-cache
+ * become + *
{...
+     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
+     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
+     *    "Cache-Control": "no-cache",
+     * ...}
+ * It does no further checking or conversion. It does not parse dates. + * It does not do '%' transforms on URLs. + * @param string An HTTP header string. + * @return A JSONObject containing the elements and attributes + * of the XML string. + * @throws JSONException + */ + public static JSONObject toJSONObject(String string) throws JSONException { + JSONObject jo = new JSONObject(); + HTTPTokener x = new HTTPTokener(string); + String token; + + token = x.nextToken(); + if (token.toUpperCase().startsWith("HTTP")) { + +// Response + + jo.put("HTTP-Version", token); + jo.put("Status-Code", x.nextToken()); + jo.put("Reason-Phrase", x.nextTo('\0')); + x.next(); + + } else { + +// Request + + jo.put("Method", token); + jo.put("Request-URI", x.nextToken()); + jo.put("HTTP-Version", x.nextToken()); + } + +// Fields + + while (x.more()) { + String name = x.nextTo(':'); + x.next(':'); + jo.put(name, x.nextTo('\0')); + x.next(); + } + return jo; + } + + + /** + * Convert a JSONObject into an HTTP header. A request header must contain + *
{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }
+ * A response header must contain + *
{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }
+ * Any other members of the JSONObject will be output as HTTP fields. + * The result will end with two CRLF pairs. + * @param jo A JSONObject + * @return An HTTP header string. + * @throws JSONException if the object does not contain enough + * information. + */ + public static String toString(JSONObject jo) throws JSONException { + Iterator keys = jo.keys(); + String string; + StringBuilder sb = new StringBuilder(); + if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { + sb.append(jo.getString("HTTP-Version")); + sb.append(' '); + sb.append(jo.getString("Status-Code")); + sb.append(' '); + sb.append(jo.getString("Reason-Phrase")); + } else if (jo.has("Method") && jo.has("Request-URI")) { + sb.append(jo.getString("Method")); + sb.append(' '); + sb.append('"'); + sb.append(jo.getString("Request-URI")); + sb.append('"'); + sb.append(' '); + sb.append(jo.getString("HTTP-Version")); + } else { + 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); + sb.append(": "); + sb.append(jo.getString(string)); + sb.append(CRLF); + } + } + sb.append(CRLF); + return sb.toString(); + } +} diff --git a/HTTPTokener.java b/org/json/HTTPTokener.java similarity index 100% rename from HTTPTokener.java rename to org/json/HTTPTokener.java diff --git a/JSONArray.java b/org/json/JSONArray.java similarity index 71% rename from JSONArray.java rename to org/json/JSONArray.java index f29085bdc..a6fbd21fc 100644 --- a/JSONArray.java +++ b/org/json/JSONArray.java @@ -28,11 +28,15 @@ of this software and associated documentation files (the "Software"), to deal import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; -import java.math.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; /** * A JSONArray is an ordered sequence of values. Its external text form is a @@ -78,7 +82,7 @@ of this software and associated documentation files (the "Software"), to deal * @author JSON.org * @version 2016-02-08 */ -public class JSONArray implements Iterable { +public class JSONArray implements Iterable, Cloneable { /** * The arrayList where the JSONArray's properties are kept. @@ -95,10 +99,8 @@ public JSONArray() { /** * Construct a JSONArray from a JSONTokener. * - * @param x - * A JSONTokener - * @throws JSONException - * If there is a syntax error. + * @param x A JSONTokener + * @throws JSONException If there is a syntax error. */ public JSONArray(JSONTokener x) throws JSONException { this(); @@ -107,7 +109,7 @@ public JSONArray(JSONTokener x) throws JSONException { } if (x.nextClean() != ']') { x.back(); - for (;;) { + for (; ; ) { if (x.nextClean() == ',') { x.back(); this.myArrayList.add(JSONObject.NULL); @@ -116,16 +118,16 @@ public JSONArray(JSONTokener x) throws JSONException { this.myArrayList.add(x.nextValue()); } switch (x.nextClean()) { - case ',': - if (x.nextClean() == ']') { + case ',': + if (x.nextClean() == ']') { + return; + } + x.back(); + break; + case ']': return; - } - x.back(); - break; - case ']': - return; - default: - throw x.syntaxError("Expected a ',' or ']'"); + default: + throw x.syntaxError("Expected a ',' or ']'"); } } } @@ -134,12 +136,10 @@ public JSONArray(JSONTokener x) throws JSONException { /** * Construct a JSONArray from a source JSON text. * - * @param source - * A string that begins with [ (left - * bracket) and ends with ] - *  (right bracket). - * @throws JSONException - * If there is a syntax error. + * @param source A string that begins with [ (left + * bracket) and ends with ] + *  (right bracket). + * @throws JSONException If there is a syntax error. */ public JSONArray(String source) throws JSONException { this(new JSONTokener(source)); @@ -148,23 +148,21 @@ public JSONArray(String source) throws JSONException { /** * Construct a JSONArray from a Collection. * - * @param collection - * A Collection. + * @param collection A Collection. */ public JSONArray(Collection collection) { this.myArrayList = new ArrayList(); if (collection != null) { - for (Object o: collection){ - this.myArrayList.add(JSONObject.wrap(o)); - } + for (Object o : collection) { + this.myArrayList.add(JSONObject.wrap(o)); + } } } /** * Construct a JSONArray from an array * - * @throws JSONException - * If not an array. + * @throws JSONException If not an array. */ public JSONArray(Object array) throws JSONException { this(); @@ -175,7 +173,7 @@ public JSONArray(Object array) throws JSONException { } } else { throw new JSONException( - "JSONArray initial value should be a string or collection or array."); + "JSONArray initial value should be a string or collection or array."); } } @@ -187,11 +185,9 @@ public Iterator iterator() { /** * Get the object value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return An object value. - * @throws JSONException - * If there is no value for the index. + * @throws JSONException If there is no value for the index. */ public Object get(int index) throws JSONException { Object object = this.opt(index); @@ -205,22 +201,20 @@ public Object get(int index) throws JSONException { * Get the boolean value associated with an index. The string values "true" * and "false" are converted to boolean. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The truth. - * @throws JSONException - * If there is no value for the index or if the value is not - * convertible to boolean. + * @throws JSONException If there is no value for the index or if the value is not + * convertible to boolean. */ public boolean getBoolean(int index) throws JSONException { Object object = this.get(index); if (object.equals(Boolean.FALSE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("false"))) { + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { return false; } else if (object.equals(Boolean.TRUE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("true"))) { + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { return true; } throw new JSONException("JSONArray[" + index + "] is not a boolean."); @@ -229,44 +223,39 @@ public boolean getBoolean(int index) throws JSONException { /** * Get the double value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException - * If the key is not found or if the value cannot be converted - * to a number. + * @throws JSONException If the key is not found or if the value cannot be converted + * to a number. */ public double getDouble(int index) throws JSONException { Object object = this.get(index); try { return object instanceof Number ? ((Number) object).doubleValue() - : Double.parseDouble((String) object); + : Double.parseDouble((String) object); } catch (Exception e) { throw new JSONException("JSONArray[" + index + "] is not a number."); } } /** - * Get the enum value associated with an index. - * - * @param clazz - * The type of enum to retrieve. - * @param index - * The index must be between 0 and length() - 1. - * @return The enum value at the index location - * @throws JSONException - * if the key is not found or if the value cannot be converted - * to an enum. - */ + * Get the enum value associated with an index. + * + * @param clazz The type of enum to retrieve. + * @param index The index must be between 0 and length() - 1. + * @return The enum value at the index location + * @throws JSONException if the key is not found or if the value cannot be converted + * to an enum. + */ public > E getEnum(Class clazz, int index) throws JSONException { E val = optEnum(clazz, index); - if(val==null) { + if (val == null) { // 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()) - + "."); + + "] is not an enum of type " + JSONObject.quote(clazz.getSimpleName()) + + "."); } return val; } @@ -274,57 +263,51 @@ public > E getEnum(Class clazz, int index) throws JSONExcep /** * Get the BigDecimal value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException - * If the key is not found or if the value cannot be converted - * to a BigDecimal. + * @throws JSONException If the key is not found or if the value cannot be converted + * to a BigDecimal. */ - public BigDecimal getBigDecimal (int index) throws JSONException { + public BigDecimal getBigDecimal(int index) throws JSONException { Object object = this.get(index); try { return new BigDecimal(object.toString()); } catch (Exception e) { throw new JSONException("JSONArray[" + index + - "] could not convert to BigDecimal."); + "] could not convert to BigDecimal."); } } /** * Get the BigInteger value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException - * If the key is not found or if the value cannot be converted - * to a BigInteger. + * @throws JSONException If the key is not found or if the value cannot be converted + * to a BigInteger. */ - public BigInteger getBigInteger (int index) throws JSONException { + public BigInteger getBigInteger(int index) throws JSONException { Object object = this.get(index); try { return new BigInteger(object.toString()); } catch (Exception e) { throw new JSONException("JSONArray[" + index + - "] could not convert to BigInteger."); + "] could not convert to BigInteger."); } } /** * Get the int value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException - * If the key is not found or if the value is not a number. + * @throws JSONException 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 { return object instanceof Number ? ((Number) object).intValue() - : Integer.parseInt((String) object); + : Integer.parseInt((String) object); } catch (Exception e) { throw new JSONException("JSONArray[" + index + "] is not a number."); } @@ -333,12 +316,10 @@ public int getInt(int index) throws JSONException { /** * Get the JSONArray associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return A JSONArray value. - * @throws JSONException - * If there is no value for the index. or if the value is not a - * JSONArray + * @throws JSONException If there is no value for the index. or if the value is not a + * JSONArray */ public JSONArray getJSONArray(int index) throws JSONException { Object object = this.get(index); @@ -351,12 +332,10 @@ public JSONArray getJSONArray(int index) throws JSONException { /** * Get the JSONObject associated with an index. * - * @param index - * subscript + * @param index subscript * @return A JSONObject value. - * @throws JSONException - * If there is no value for the index or if the value is not a - * JSONObject + * @throws JSONException If there is no value for the index or if the value is not a + * JSONObject */ public JSONObject getJSONObject(int index) throws JSONException { Object object = this.get(index); @@ -369,18 +348,16 @@ public JSONObject getJSONObject(int index) throws JSONException { /** * Get the long value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException - * If the key is not found or if the value cannot be converted - * to a number. + * @throws JSONException If the key is not found or if the value cannot be converted + * to a number. */ public long getLong(int index) throws JSONException { Object object = this.get(index); try { return object instanceof Number ? ((Number) object).longValue() - : Long.parseLong((String) object); + : Long.parseLong((String) object); } catch (Exception e) { throw new JSONException("JSONArray[" + index + "] is not a number."); } @@ -389,11 +366,9 @@ public long getLong(int index) throws JSONException { /** * Get the string associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return A string value. - * @throws JSONException - * If there is no string value for the index. + * @throws JSONException If there is no string value for the index. */ public String getString(int index) throws JSONException { Object object = this.get(index); @@ -406,8 +381,7 @@ public String getString(int index) throws JSONException { /** * Determine if the value is null. * - * @param index - * The index must be between 0 and length() - 1. + * @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. */ public boolean isNull(int index) { @@ -419,11 +393,9 @@ public boolean isNull(int index) { * separator string is inserted between each element. Warning: * This method assumes that the data structure is acyclical. * - * @param separator - * A string that will be inserted between the elements. + * @param separator A string that will be inserted between the elements. * @return a string. - * @throws JSONException - * If the array contains an invalid number. + * @throws JSONException If the array contains an invalid number. */ public String join(String separator) throws JSONException { int len = this.length(); @@ -450,13 +422,12 @@ public int length() { /** * Get the optional object value associated with an index. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return An object value, or null if there is no object at that index. */ public Object opt(int index) { return (index < 0 || index >= this.length()) ? null : this.myArrayList - .get(index); + .get(index); } /** @@ -464,8 +435,7 @@ public Object opt(int index) { * if there is no value at that index, or if the value is not Boolean.TRUE * or the String "true". * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return The truth. */ public boolean optBoolean(int index) { @@ -477,10 +447,8 @@ public boolean optBoolean(int index) { * defaultValue if there is no value at that index or if it is not a Boolean * or the String "true" or "false" (case insensitive). * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * A boolean default. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue A boolean default. * @return The truth. */ public boolean optBoolean(int index, boolean defaultValue) { @@ -496,8 +464,7 @@ public boolean optBoolean(int index, boolean defaultValue) { * 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. + * @param index The index must be between 0 and length() - 1. * @return The value. */ public double optDouble(int index) { @@ -509,10 +476,8 @@ public double optDouble(int index) { * 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. + * @param index subscript + * @param defaultValue The default value. * @return The value. */ public double optDouble(int index, double defaultValue) { @@ -528,8 +493,7 @@ public double optDouble(int index, double defaultValue) { * 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. + * @param index The index must be between 0 and length() - 1. * @return The value. */ public int optInt(int index) { @@ -541,10 +505,8 @@ public int optInt(int index) { * 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. - * @param defaultValue - * The default value. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. * @return The value. */ public int optInt(int index, int defaultValue) { @@ -557,11 +519,9 @@ public int optInt(int index, int defaultValue) { /** * Get the enum value associated with a key. - * - * @param clazz - * The type of enum to retrieve. - * @param index - * The index must be between 0 and length() - 1. + * + * @param clazz The type of enum to retrieve. + * @param index The index must be between 0 and length() - 1. * @return The enum value at the index location or null if not found */ public > E optEnum(Class clazz, int index) { @@ -570,15 +530,12 @@ public > E optEnum(Class clazz, int index) { /** * Get the enum value associated with a key. - * - * @param clazz - * The type of enum to retrieve. - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default in case the value is not found + * + * @param clazz The type of enum to retrieve. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default in case the value is not found * @return The enum value at the index location or defaultValue if - * the value is not found or cannot be assigned to clazz + * the value is not found or cannot be assigned to clazz */ public > E optEnum(Class clazz, int index, E defaultValue) { try { @@ -602,14 +559,12 @@ public > E optEnum(Class clazz, int index, E defaultValue) /** - * Get the optional BigInteger value associated with an index. The - * defaultValue is returned if there is no value for the index, or if the + * Get the optional BigInteger 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 - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default value. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. * @return The value. */ public BigInteger optBigInteger(int index, BigInteger defaultValue) { @@ -621,14 +576,12 @@ public BigInteger optBigInteger(int index, BigInteger 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 + * 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. * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default value. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. * @return The value. */ public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { @@ -642,10 +595,9 @@ public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { /** * Get the optional JSONArray associated with an index. * - * @param index - * subscript + * @param index subscript * @return A JSONArray value, or null if the index has no value, or if the - * value is not a JSONArray. + * value is not a JSONArray. */ public JSONArray optJSONArray(int index) { Object o = this.opt(index); @@ -657,8 +609,7 @@ public JSONArray optJSONArray(int index) { * the key is not found, or null if the index has no value, or if the value * is not a JSONObject. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return A JSONObject value. */ public JSONObject optJSONObject(int index) { @@ -671,8 +622,7 @@ public JSONObject optJSONObject(int index) { * 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. + * @param index The index must be between 0 and length() - 1. * @return The value. */ public long optLong(int index) { @@ -684,10 +634,8 @@ public long optLong(int index) { * 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. - * @param defaultValue - * The default value. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. * @return The value. */ public long optLong(int index, long defaultValue) { @@ -703,8 +651,7 @@ public long optLong(int index, long defaultValue) { * 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. * - * @param index - * The index must be between 0 and length() - 1. + * @param index The index must be between 0 and length() - 1. * @return A String value. */ public String optString(int index) { @@ -715,23 +662,20 @@ public String optString(int index) { * Get the optional string associated with an index. The defaultValue is * returned if the key is not found. * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default value. + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. * @return A String value. */ public String optString(int index, String defaultValue) { Object object = this.opt(index); return JSONObject.NULL.equals(object) ? defaultValue : object - .toString(); + .toString(); } /** * Append a boolean value. This increases the array's length by one. * - * @param value - * A boolean value. + * @param value A boolean value. * @return this. */ public JSONArray put(boolean value) { @@ -743,8 +687,7 @@ public JSONArray put(boolean value) { * Put a value in the JSONArray, where the value will be a JSONArray which * is produced from a Collection. * - * @param value - * A Collection value. + * @param value A Collection value. * @return this. */ public JSONArray put(Collection value) { @@ -755,11 +698,9 @@ public JSONArray put(Collection value) { /** * Append a double value. This increases the array's length by one. * - * @param value - * A double value. - * @throws JSONException - * if the value is not finite. + * @param value A double value. * @return this. + * @throws JSONException if the value is not finite. */ public JSONArray put(double value) throws JSONException { Double d = new Double(value); @@ -771,8 +712,7 @@ public JSONArray put(double value) throws JSONException { /** * Append an int value. This increases the array's length by one. * - * @param value - * An int value. + * @param value An int value. * @return this. */ public JSONArray put(int value) { @@ -783,8 +723,7 @@ public JSONArray put(int value) { /** * Append an long value. This increases the array's length by one. * - * @param value - * A long value. + * @param value A long value. * @return this. */ public JSONArray put(long value) { @@ -796,8 +735,7 @@ public JSONArray put(long value) { * Put a value in the JSONArray, where the value will be a JSONObject which * is produced from a Map. * - * @param value - * A Map value. + * @param value A Map value. * @return this. */ public JSONArray put(Map value) { @@ -808,10 +746,9 @@ public JSONArray put(Map value) { /** * Append an object value. This increases the array's length by one. * - * @param value - * An object value. The value should be a Boolean, Double, - * Integer, JSONArray, JSONObject, Long, or String, or the - * JSONObject.NULL object. + * @param value An object value. The value should be a Boolean, Double, + * Integer, JSONArray, JSONObject, Long, or String, or the + * JSONObject.NULL object. * @return this. */ public JSONArray put(Object value) { @@ -824,13 +761,10 @@ public JSONArray put(Object value) { * 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 boolean value. + * @param index The subscript. + * @param value A boolean value. * @return this. - * @throws JSONException - * If the index is negative. + * @throws JSONException If the index is negative. */ public JSONArray put(int index, boolean value) throws JSONException { this.put(index, value ? Boolean.TRUE : Boolean.FALSE); @@ -841,13 +775,10 @@ public JSONArray put(int index, boolean value) throws JSONException { * Put a value in the JSONArray, where the value will be a JSONArray which * is produced from a Collection. * - * @param index - * The subscript. - * @param value - * A Collection value. + * @param index The subscript. + * @param value A Collection value. * @return this. - * @throws JSONException - * If the index is negative or if the value is not finite. + * @throws JSONException If the index is negative or if the value is not finite. */ public JSONArray put(int index, Collection value) throws JSONException { this.put(index, new JSONArray(value)); @@ -859,13 +790,10 @@ public JSONArray put(int index, Collection value) throws JSONException { * the JSONArray, then null elements will be added as necessary to pad it * out. * - * @param index - * The subscript. - * @param value - * A double value. + * @param index The subscript. + * @param value A double value. * @return this. - * @throws JSONException - * If the index is negative or if the value is not finite. + * @throws JSONException If the index is negative or if the value is not finite. */ public JSONArray put(int index, double value) throws JSONException { this.put(index, new Double(value)); @@ -877,13 +805,10 @@ public JSONArray put(int index, double value) throws JSONException { * the JSONArray, then null elements will be added as necessary to pad it * out. * - * @param index - * The subscript. - * @param value - * An int value. + * @param index The subscript. + * @param value An int value. * @return this. - * @throws JSONException - * If the index is negative. + * @throws JSONException If the index is negative. */ public JSONArray put(int index, int value) throws JSONException { this.put(index, new Integer(value)); @@ -895,13 +820,10 @@ public JSONArray put(int index, int value) throws JSONException { * the JSONArray, then null elements will be added as necessary to pad it * out. * - * @param index - * The subscript. - * @param value - * A long value. + * @param index The subscript. + * @param value A long value. * @return this. - * @throws JSONException - * If the index is negative. + * @throws JSONException If the index is negative. */ public JSONArray put(int index, long value) throws JSONException { this.put(index, new Long(value)); @@ -912,14 +834,11 @@ public JSONArray put(int index, long value) throws JSONException { * Put a value in the JSONArray, where the value will be a JSONObject that * is produced from a Map. * - * @param index - * The subscript. - * @param value - * The Map value. + * @param index The subscript. + * @param value The Map value. * @return this. - * @throws JSONException - * If the index is negative or if the the value is an invalid - * number. + * @throws JSONException If the index is negative or if the the value is an invalid + * number. */ public JSONArray put(int index, Map value) throws JSONException { this.put(index, new JSONObject(value)); @@ -931,16 +850,13 @@ public JSONArray put(int index, Map value) throws JSONException { * than the length of the JSONArray, then null elements will be added as * necessary to pad it out. * - * @param index - * The subscript. - * @param value - * The value to put into the array. The value should be a - * Boolean, Double, Integer, JSONArray, JSONObject, Long, or - * String, or the JSONObject.NULL object. + * @param index The subscript. + * @param value The value to put into the array. The value should be a + * Boolean, Double, Integer, JSONArray, JSONObject, Long, or + * String, or the JSONObject.NULL object. * @return this. - * @throws JSONException - * If the index is negative or if the the value is an invalid - * number. + * @throws JSONException If the index is negative or if the the value is an invalid + * number. */ public JSONArray put(int index, Object value) throws JSONException { JSONObject.testValidity(value); @@ -961,10 +877,9 @@ public JSONArray put(int index, Object value) throws JSONException { /** * Remove an index and close the hole. * - * @param index - * The index of the element to be removed. + * @param index The index of the element to be removed. * @return The value that was associated with the index, or null if there - * was no value. + * was no value. */ public Object remove(int index) { return index >= 0 && index < this.length() @@ -984,18 +899,18 @@ public boolean similar(Object other) { return false; } int len = this.length(); - if (len != ((JSONArray)other).length()) { + if (len != ((JSONArray) other).length()) { return false; } for (int i = 0; i < len; i += 1) { Object valueThis = this.get(i); - Object valueOther = ((JSONArray)other).get(i); + Object valueOther = ((JSONArray) other).get(i); if (valueThis instanceof JSONObject) { - if (!((JSONObject)valueThis).similar(valueOther)) { + if (!((JSONObject) valueThis).similar(valueOther)) { return false; } } else if (valueThis instanceof JSONArray) { - if (!((JSONArray)valueThis).similar(valueOther)) { + if (!((JSONArray) valueThis).similar(valueOther)) { return false; } } else if (!valueThis.equals(valueOther)) { @@ -1009,13 +924,11 @@ public boolean similar(Object other) { * Produce a JSONObject by combining a JSONArray of names with the values of * this JSONArray. * - * @param names - * A JSONArray containing a list of key strings. These will be - * paired with the values. + * @param names A JSONArray containing a list of key strings. These will be + * paired with the values. * @return A JSONObject, or null if there are no names or if this JSONArray - * has no values. - * @throws JSONException - * If any of the names are null. + * has no values. + * @throws JSONException If any of the names are null. */ public JSONObject toJSONObject(JSONArray names) throws JSONException { if (names == null || names.length() == 0 || this.length() == 0) { @@ -1037,7 +950,7 @@ public JSONObject toJSONObject(JSONArray names) throws JSONException { * Warning: This method assumes that the data structure is acyclical. * * @return a printable, displayable, transmittable representation of the - * array. + * array. */ public String toString() { try { @@ -1051,12 +964,11 @@ public String toString() { * Make a prettyprinted JSON text of this JSONArray. Warning: This method * assumes that the data structure is acyclical. * - * @param indentFactor - * The number of spaces to add to each level of indentation. + * @param indentFactor The number of spaces to add to each level of indentation. * @return a printable, displayable, transmittable representation of the - * object, beginning with [ (left - * bracket) and ending with ] - *  (right bracket). + * object, beginning with [ (left + * bracket) and ending with ] + *  (right bracket). * @throws JSONException */ public String toString(int indentFactor) throws JSONException { @@ -1085,17 +997,14 @@ public Writer write(Writer writer) throws JSONException { *

* Warning: This method assumes that the data structure is acyclical. * - * @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. + * @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. * @return The writer. * @throws JSONException */ public Writer write(Writer writer, int indentFactor, int indent) - throws JSONException { + throws JSONException { try { boolean commanate = false; int length = this.length(); @@ -1103,7 +1012,7 @@ public Writer write(Writer writer, int indentFactor, int indent) if (length == 1) { JSONObject.writeValue(writer, this.myArrayList.get(0), - indentFactor, indent); + indentFactor, indent); } else if (length != 0) { final int newindent = indent + indentFactor; @@ -1116,7 +1025,7 @@ public Writer write(Writer writer, int indentFactor, int indent) } JSONObject.indent(writer, newindent); JSONObject.writeValue(writer, this.myArrayList.get(i), - indentFactor, newindent); + indentFactor, newindent); commanate = true; } if (indentFactor > 0) { @@ -1130,4 +1039,46 @@ public Writer write(Writer writer, int indentFactor, int indent) throw new JSONException(e); } } + + public boolean isEmpty() { + return this.length() == 0; + } + + public Stream stream() { + return StreamSupport.stream(Spliterators.spliterator(this.iterator(), this.length(), Spliterator.ORDERED), false); + } + + public JSONArray clone() { + return this.stream().collect(new Collector<>()); + } + + public class Collector implements java.util.stream.Collector { + @Override + public Supplier supplier() { + return JSONArray::new; + } + + @Override + public BiConsumer accumulator() { + return JSONArray::put; + } + + @Override + public BinaryOperator combiner() { + return (arr1, arr2) -> { + arr2.forEach(arr1::put); + return arr1; + }; + } + + @Override + public Function finisher() { + return arr -> arr; + } + + @Override + public Set characteristics() { + return EnumSet.of(Characteristics.UNORDERED); + } + } } diff --git a/JSONException.java b/org/json/JSONException.java similarity index 100% rename from JSONException.java rename to org/json/JSONException.java diff --git a/JSONML.java b/org/json/JSONML.java similarity index 100% rename from JSONML.java rename to org/json/JSONML.java diff --git a/JSONObject.java b/org/json/JSONObject.java similarity index 95% rename from JSONObject.java rename to org/json/JSONObject.java index 1ce25401f..ee1951439 100644 --- a/JSONObject.java +++ b/org/json/JSONObject.java @@ -32,15 +32,13 @@ of this software and associated documentation files (the "Software"), to deal import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.ResourceBundle; -import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; /** * A JSONObject is an unordered collection of name/value pairs. Its external @@ -95,7 +93,7 @@ of this software and associated documentation files (the "Software"), to deal * @author JSON.org * @version 2016-02-08 */ -public class JSONObject { +public class JSONObject implements Cloneable { /** * JSONObject.NULL is equivalent to the value that JavaScript calls null, * whilst Java's null is equivalent to the value that JavaScript calls @@ -150,6 +148,22 @@ public String toString() { */ public static final Object NULL = new Null(); + + public enum MergeMode { + /** + * Trying to add duplicate keys will be ignored and previous values will be used. + */ + SKIP_DUPLICATES, + /** + * Trying to add duplicate keys causes replacing old values. + */ + REPLACE_DUPLICATES, + /** + * Trying to add duplicate keys changes JSONObject value to JSONArray containing all values. + */ + APPEND_DUPLICATES + } + /** * Construct an empty JSONObject. */ @@ -1838,4 +1852,67 @@ public Writer write(Writer writer, int indentFactor, int indent) throw new JSONException(exception); } } + + + public JSONObject merge(JSONObject json, MergeMode mergeMode) { + if (json != null && json.length() > 0) { + if (mergeMode == null) { + mergeMode = MergeMode.SKIP_DUPLICATES; + } + + switch (mergeMode) { + case SKIP_DUPLICATES: + json.keySet().stream().filter(k -> !this.has(k)).forEach(k -> this.put(k, json.get(k))); + break; + + case REPLACE_DUPLICATES: + json.keySet().forEach(k -> this.put(k, json.get(k))); + break; + + case APPEND_DUPLICATES: + json.keySet().forEach(k -> this.accumulate(k, json.get(k))); + break; + } + } + return this; + } + + public boolean isEmpty() { + return this.length() == 0; + } + + public Stream> stream() { + return this.map.entrySet().stream(); + } + + public JSONObject clone() { + return this.map.entrySet().stream().collect(new Collector<>()); + } + + public class Collector implements java.util.stream.Collector, JSONObject, JSONObject> { + @Override + public Supplier supplier() { + return JSONObject::new; + } + + @Override + public BiConsumer> accumulator() { + return (json, entry) -> json.put(entry.getKey(), entry.getValue()); + } + + @Override + public BinaryOperator combiner() { + return (json1, json2) -> json1.merge(json2, JSONObject.MergeMode.REPLACE_DUPLICATES); + } + + @Override + public Function finisher() { + return json -> json; + } + + @Override + public Set characteristics() { + return EnumSet.of(Characteristics.UNORDERED); + } + } } diff --git a/JSONString.java b/org/json/JSONString.java similarity index 100% rename from JSONString.java rename to org/json/JSONString.java diff --git a/JSONStringer.java b/org/json/JSONStringer.java similarity index 97% rename from JSONStringer.java rename to org/json/JSONStringer.java index 5fbc96a9a..3ce1d5534 100644 --- a/JSONStringer.java +++ b/org/json/JSONStringer.java @@ -1,78 +1,78 @@ -package org.json; - -/* -Copyright (c) 2006 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 java.io.StringWriter; - -/** - * JSONStringer provides a quick and convenient way of producing JSON text. - * The texts produced strictly conform to JSON syntax rules. No whitespace is - * added, so the results are ready for transmission or storage. Each instance of - * JSONStringer can produce one JSON text. - *

- * A JSONStringer instance provides a value method for appending - * values to the - * text, and a key - * method for adding keys before values in objects. There are array - * and endArray methods that make and bound array values, and - * object and endObject methods which make and bound - * object values. All of these methods return the JSONWriter instance, - * permitting cascade style. For example,

- * myString = new JSONStringer()
- *     .object()
- *         .key("JSON")
- *         .value("Hello, World!")
- *     .endObject()
- *     .toString();
which produces the string
- * {"JSON":"Hello, World!"}
- *

- * The first method called must be array or object. - * There are no methods for adding commas or colons. JSONStringer adds them for - * you. Objects and arrays can be nested up to 20 levels deep. - *

- * This can sometimes be easier than using a JSONObject to build a string. - * @author JSON.org - * @version 2015-12-09 - */ -public class JSONStringer extends JSONWriter { - /** - * Make a fresh JSONStringer. It can be used to build one JSON text. - */ - public JSONStringer() { - super(new StringWriter()); - } - - /** - * Return the JSON text. This method is used to obtain the product of the - * JSONStringer instance. It will return null if there was a - * problem in the construction of the JSON text (such as the calls to - * array were not properly balanced with calls to - * endArray). - * @return The JSON text. - */ - public String toString() { - return this.mode == 'd' ? this.writer.toString() : null; - } -} +package org.json; + +/* +Copyright (c) 2006 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 java.io.StringWriter; + +/** + * JSONStringer provides a quick and convenient way of producing JSON text. + * The texts produced strictly conform to JSON syntax rules. No whitespace is + * added, so the results are ready for transmission or storage. Each instance of + * JSONStringer can produce one JSON text. + *

+ * A JSONStringer instance provides a value method for appending + * values to the + * text, and a key + * method for adding keys before values in objects. There are array + * and endArray methods that make and bound array values, and + * object and endObject methods which make and bound + * object values. All of these methods return the JSONWriter instance, + * permitting cascade style. For example,

+ * myString = new JSONStringer()
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject()
+ *     .toString();
which produces the string
+ * {"JSON":"Hello, World!"}
+ *

+ * The first method called must be array or object. + * There are no methods for adding commas or colons. JSONStringer adds them for + * you. Objects and arrays can be nested up to 20 levels deep. + *

+ * This can sometimes be easier than using a JSONObject to build a string. + * @author JSON.org + * @version 2015-12-09 + */ +public class JSONStringer extends JSONWriter { + /** + * Make a fresh JSONStringer. It can be used to build one JSON text. + */ + public JSONStringer() { + super(new StringWriter()); + } + + /** + * Return the JSON text. This method is used to obtain the product of the + * JSONStringer instance. It will return null if there was a + * problem in the construction of the JSON text (such as the calls to + * array were not properly balanced with calls to + * endArray). + * @return The JSON text. + */ + public String toString() { + return this.mode == 'd' ? this.writer.toString() : null; + } +} diff --git a/JSONTokener.java b/org/json/JSONTokener.java similarity index 98% rename from JSONTokener.java rename to org/json/JSONTokener.java index 32548ed9f..42ea65e22 100644 --- a/JSONTokener.java +++ b/org/json/JSONTokener.java @@ -1,11 +1,6 @@ package org.json; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; +import java.io.*; /* Copyright (c) 2002 JSON.org diff --git a/JSONWriter.java b/org/json/JSONWriter.java similarity index 96% rename from JSONWriter.java rename to org/json/JSONWriter.java index 09d113030..dd656001d 100644 --- a/JSONWriter.java +++ b/org/json/JSONWriter.java @@ -1,327 +1,327 @@ -package org.json; - -import java.io.IOException; -import java.io.Writer; - -/* -Copyright (c) 2006 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. -*/ - -/** - * JSONWriter provides a quick and convenient way of producing JSON text. - * The texts produced strictly conform to JSON syntax rules. No whitespace is - * added, so the results are ready for transmission or storage. Each instance of - * JSONWriter can produce one JSON text. - *

- * A JSONWriter instance provides a value method for appending - * values to the - * text, and a key - * method for adding keys before values in objects. There are array - * and endArray methods that make and bound array values, and - * object and endObject methods which make and bound - * object values. All of these methods return the JSONWriter instance, - * permitting a cascade style. For example,

- * new JSONWriter(myWriter)
- *     .object()
- *         .key("JSON")
- *         .value("Hello, World!")
- *     .endObject();
which writes
- * {"JSON":"Hello, World!"}
- *

- * The first method called must be array or object. - * 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. - *

- * This can sometimes be easier than using a JSONObject to build a string. - * @author JSON.org - * @version 2015-12-09 - */ -public class JSONWriter { - private static final int maxdepth = 200; - - /** - * The comma flag determines if a comma should be output before the next - * value. - */ - private boolean comma; - - /** - * The current mode. Values: - * 'a' (array), - * 'd' (done), - * 'i' (initial), - * 'k' (key), - * 'o' (object). - */ - protected char mode; - - /** - * The object/array stack. - */ - private final JSONObject stack[]; - - /** - * The stack top index. A value of 0 indicates that the stack is empty. - */ - private int top; - - /** - * The writer that will receive the output. - */ - protected Writer writer; - - /** - * Make a fresh JSONWriter. It can be used to build one JSON text. - */ - public JSONWriter(Writer w) { - this.comma = false; - this.mode = 'i'; - this.stack = new JSONObject[maxdepth]; - this.top = 0; - this.writer = w; - } - - /** - * Append a value. - * @param string A string value. - * @return this - * @throws JSONException If the value is out of sequence. - */ - private JSONWriter append(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null pointer"); - } - if (this.mode == 'o' || this.mode == 'a') { - try { - if (this.comma && this.mode == 'a') { - this.writer.write(','); - } - this.writer.write(string); - } catch (IOException e) { - throw new JSONException(e); - } - if (this.mode == 'o') { - this.mode = 'k'; - } - this.comma = true; - return this; - } - throw new JSONException("Value out of sequence."); - } - - /** - * Begin appending a new array. All values until the balancing - * endArray will be appended to this array. The - * endArray method must be called to mark the array's end. - * @return this - * @throws JSONException If the nesting is too deep, or if the object is - * started in the wrong place (for example as a key or after the end of the - * outermost array or object). - */ - public JSONWriter array() throws JSONException { - if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { - this.push(null); - this.append("["); - this.comma = false; - return this; - } - throw new JSONException("Misplaced array."); - } - - /** - * End something. - * @param mode 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' - ? "Misplaced endArray." - : "Misplaced endObject."); - } - this.pop(mode); - try { - this.writer.write(c); - } catch (IOException e) { - throw new JSONException(e); - } - this.comma = true; - return this; - } - - /** - * End an array. This method most be called to balance calls to - * array. - * @return this - * @throws JSONException If incorrectly nested. - */ - public JSONWriter endArray() throws JSONException { - return this.end('a', ']'); - } - - /** - * End an object. This method most be called to balance calls to - * object. - * @return this - * @throws JSONException If incorrectly nested. - */ - public JSONWriter endObject() throws JSONException { - return this.end('k', '}'); - } - - /** - * Append a key. The key will be associated with the next value. In an - * object, every value must be preceded by a key. - * @param string A key string. - * @return this - * @throws JSONException If the key is out of place. For example, keys - * do not belong in arrays or if the key is null. - */ - public JSONWriter key(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null key."); - } - if (this.mode == 'k') { - try { - this.stack[this.top - 1].putOnce(string, Boolean.TRUE); - if (this.comma) { - this.writer.write(','); - } - this.writer.write(JSONObject.quote(string)); - this.writer.write(':'); - this.comma = false; - this.mode = 'o'; - return this; - } catch (IOException e) { - throw new JSONException(e); - } - } - throw new JSONException("Misplaced key."); - } - - - /** - * Begin appending a new object. All keys and values until the balancing - * endObject will be appended to this object. The - * endObject method must be called to mark the object's end. - * @return this - * @throws JSONException If the nesting is too deep, or if the object is - * started in the wrong place (for example as a key or after the end of the - * outermost array or object). - */ - public JSONWriter object() throws JSONException { - if (this.mode == 'i') { - this.mode = 'o'; - } - if (this.mode == 'o' || this.mode == 'a') { - this.append("{"); - this.push(new JSONObject()); - this.comma = false; - return this; - } - throw new JSONException("Misplaced object."); - - } - - - /** - * Pop an array or object scope. - * @param c The scope to close. - * @throws JSONException If nesting is wrong. - */ - private void pop(char c) throws JSONException { - if (this.top <= 0) { - throw new JSONException("Nesting error."); - } - char m = this.stack[this.top - 1] == null ? 'a' : 'k'; - if (m != c) { - throw new JSONException("Nesting error."); - } - this.top -= 1; - this.mode = this.top == 0 - ? 'd' - : this.stack[this.top - 1] == null - ? 'a' - : 'k'; - } - - /** - * Push an array or object scope. - * @param jo The scope to open. - * @throws JSONException If nesting is too deep. - */ - private void push(JSONObject jo) throws JSONException { - if (this.top >= maxdepth) { - throw new JSONException("Nesting too deep."); - } - this.stack[this.top] = jo; - this.mode = jo == null ? 'a' : 'k'; - this.top += 1; - } - - - /** - * Append either the value true or the value - * false. - * @param b A boolean. - * @return this - * @throws JSONException - */ - public JSONWriter value(boolean b) throws JSONException { - return this.append(b ? "true" : "false"); - } - - /** - * Append a double value. - * @param d A double. - * @return this - * @throws JSONException If the number is not finite. - */ - public JSONWriter value(double d) throws JSONException { - return this.value(new Double(d)); - } - - /** - * Append a long value. - * @param l A long. - * @return this - * @throws JSONException - */ - public JSONWriter value(long l) throws JSONException { - return this.append(Long.toString(l)); - } - - - /** - * Append an object value. - * @param object The object to append. It can be null, or a Boolean, Number, - * String, JSONObject, or JSONArray, or an object that implements JSONString. - * @return this - * @throws JSONException If the value is out of sequence. - */ - public JSONWriter value(Object object) throws JSONException { - return this.append(JSONObject.valueToString(object)); - } -} +package org.json; + +import java.io.IOException; +import java.io.Writer; + +/* +Copyright (c) 2006 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. +*/ + +/** + * JSONWriter provides a quick and convenient way of producing JSON text. + * The texts produced strictly conform to JSON syntax rules. No whitespace is + * added, so the results are ready for transmission or storage. Each instance of + * JSONWriter can produce one JSON text. + *

+ * A JSONWriter instance provides a value method for appending + * values to the + * text, and a key + * method for adding keys before values in objects. There are array + * and endArray methods that make and bound array values, and + * object and endObject methods which make and bound + * object values. All of these methods return the JSONWriter instance, + * permitting a cascade style. For example,

+ * new JSONWriter(myWriter)
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject();
which writes
+ * {"JSON":"Hello, World!"}
+ *

+ * The first method called must be array or object. + * 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. + *

+ * This can sometimes be easier than using a JSONObject to build a string. + * @author JSON.org + * @version 2015-12-09 + */ +public class JSONWriter { + private static final int maxdepth = 200; + + /** + * The comma flag determines if a comma should be output before the next + * value. + */ + private boolean comma; + + /** + * The current mode. Values: + * 'a' (array), + * 'd' (done), + * 'i' (initial), + * 'k' (key), + * 'o' (object). + */ + protected char mode; + + /** + * The object/array stack. + */ + private final JSONObject stack[]; + + /** + * The stack top index. A value of 0 indicates that the stack is empty. + */ + private int top; + + /** + * The writer that will receive the output. + */ + protected Writer writer; + + /** + * Make a fresh JSONWriter. It can be used to build one JSON text. + */ + public JSONWriter(Writer w) { + this.comma = false; + this.mode = 'i'; + this.stack = new JSONObject[maxdepth]; + this.top = 0; + this.writer = w; + } + + /** + * Append a value. + * @param string A string value. + * @return this + * @throws JSONException If the value is out of sequence. + */ + private JSONWriter append(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null pointer"); + } + if (this.mode == 'o' || this.mode == 'a') { + try { + if (this.comma && this.mode == 'a') { + this.writer.write(','); + } + this.writer.write(string); + } catch (IOException e) { + throw new JSONException(e); + } + if (this.mode == 'o') { + this.mode = 'k'; + } + this.comma = true; + return this; + } + throw new JSONException("Value out of sequence."); + } + + /** + * Begin appending a new array. All values until the balancing + * endArray will be appended to this array. The + * endArray method must be called to mark the array's end. + * @return this + * @throws JSONException If the nesting is too deep, or if the object is + * started in the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter array() throws JSONException { + if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { + this.push(null); + this.append("["); + this.comma = false; + return this; + } + throw new JSONException("Misplaced array."); + } + + /** + * End something. + * @param mode 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' + ? "Misplaced endArray." + : "Misplaced endObject."); + } + this.pop(mode); + try { + this.writer.write(c); + } catch (IOException e) { + throw new JSONException(e); + } + this.comma = true; + return this; + } + + /** + * End an array. This method most be called to balance calls to + * array. + * @return this + * @throws JSONException If incorrectly nested. + */ + public JSONWriter endArray() throws JSONException { + return this.end('a', ']'); + } + + /** + * End an object. This method most be called to balance calls to + * object. + * @return this + * @throws JSONException If incorrectly nested. + */ + public JSONWriter endObject() throws JSONException { + return this.end('k', '}'); + } + + /** + * Append a key. The key will be associated with the next value. In an + * object, every value must be preceded by a key. + * @param string A key string. + * @return this + * @throws JSONException If the key is out of place. For example, keys + * do not belong in arrays or if the key is null. + */ + public JSONWriter key(String string) throws JSONException { + if (string == null) { + throw new JSONException("Null key."); + } + if (this.mode == 'k') { + try { + this.stack[this.top - 1].putOnce(string, Boolean.TRUE); + if (this.comma) { + this.writer.write(','); + } + this.writer.write(JSONObject.quote(string)); + this.writer.write(':'); + this.comma = false; + this.mode = 'o'; + return this; + } catch (IOException e) { + throw new JSONException(e); + } + } + throw new JSONException("Misplaced key."); + } + + + /** + * Begin appending a new object. All keys and values until the balancing + * endObject will be appended to this object. The + * endObject method must be called to mark the object's end. + * @return this + * @throws JSONException If the nesting is too deep, or if the object is + * started in the wrong place (for example as a key or after the end of the + * outermost array or object). + */ + public JSONWriter object() throws JSONException { + if (this.mode == 'i') { + this.mode = 'o'; + } + if (this.mode == 'o' || this.mode == 'a') { + this.append("{"); + this.push(new JSONObject()); + this.comma = false; + return this; + } + throw new JSONException("Misplaced object."); + + } + + + /** + * Pop an array or object scope. + * @param c The scope to close. + * @throws JSONException If nesting is wrong. + */ + private void pop(char c) throws JSONException { + if (this.top <= 0) { + throw new JSONException("Nesting error."); + } + char m = this.stack[this.top - 1] == null ? 'a' : 'k'; + if (m != c) { + throw new JSONException("Nesting error."); + } + this.top -= 1; + this.mode = this.top == 0 + ? 'd' + : this.stack[this.top - 1] == null + ? 'a' + : 'k'; + } + + /** + * Push an array or object scope. + * @param jo The scope to open. + * @throws JSONException If nesting is too deep. + */ + private void push(JSONObject jo) throws JSONException { + if (this.top >= maxdepth) { + throw new JSONException("Nesting too deep."); + } + this.stack[this.top] = jo; + this.mode = jo == null ? 'a' : 'k'; + this.top += 1; + } + + + /** + * Append either the value true or the value + * false. + * @param b A boolean. + * @return this + * @throws JSONException + */ + public JSONWriter value(boolean b) throws JSONException { + return this.append(b ? "true" : "false"); + } + + /** + * Append a double value. + * @param d A double. + * @return this + * @throws JSONException If the number is not finite. + */ + public JSONWriter value(double d) throws JSONException { + return this.value(new Double(d)); + } + + /** + * Append a long value. + * @param l A long. + * @return this + * @throws JSONException + */ + public JSONWriter value(long l) throws JSONException { + return this.append(Long.toString(l)); + } + + + /** + * Append an object value. + * @param object The object to append. It can be null, or a Boolean, Number, + * String, JSONObject, or JSONArray, or an object that implements JSONString. + * @return this + * @throws JSONException If the value is out of sequence. + */ + public JSONWriter value(Object object) throws JSONException { + return this.append(JSONObject.valueToString(object)); + } +} diff --git a/Property.java b/org/json/Property.java similarity index 100% rename from Property.java rename to org/json/Property.java diff --git a/README b/org/json/README similarity index 100% rename from README rename to org/json/README diff --git a/XML.java b/org/json/XML.java similarity index 100% rename from XML.java rename to org/json/XML.java diff --git a/XMLTokener.java b/org/json/XMLTokener.java similarity index 100% rename from XMLTokener.java rename to org/json/XMLTokener.java From 766445cfceda5533de1fbcbef2de64ada83bcb62 Mon Sep 17 00:00:00 2001 From: AmirHossein Date: Wed, 24 Feb 2016 18:05:26 +0330 Subject: [PATCH 58/59] merge --- org/json/JSONArray.java | 4 ++-- org/json/JSONObject.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/org/json/JSONArray.java b/org/json/JSONArray.java index a6fbd21fc..762b077e6 100644 --- a/org/json/JSONArray.java +++ b/org/json/JSONArray.java @@ -93,7 +93,7 @@ public class JSONArray implements Iterable, Cloneable { * Construct an empty JSONArray. */ public JSONArray() { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList<>(); } /** @@ -151,7 +151,7 @@ public JSONArray(String source) throws JSONException { * @param collection A Collection. */ public JSONArray(Collection collection) { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList<>(); if (collection != null) { for (Object o : collection) { this.myArrayList.add(JSONObject.wrap(o)); diff --git a/org/json/JSONObject.java b/org/json/JSONObject.java index ee1951439..8deed569e 100644 --- a/org/json/JSONObject.java +++ b/org/json/JSONObject.java @@ -168,7 +168,7 @@ public enum MergeMode { * Construct an empty JSONObject. */ public JSONObject() { - this.map = new HashMap(); + this.map = new HashMap<>(); } /** @@ -254,7 +254,7 @@ public JSONObject(JSONTokener x) throws JSONException { * the JSONObject. */ public JSONObject(Map map) { - this.map = new HashMap(); + this.map = new HashMap<>(); if (map != null) { for (final Entry e : map.entrySet()) { final Object value = e.getValue(); From 429cd0bf3ea1f98409acaed2c46e78981935c78a Mon Sep 17 00:00:00 2001 From: AmirHossein Date: Wed, 24 Feb 2016 18:31:00 +0330 Subject: [PATCH 59/59] Optional getters added --- org/json/JSONArray.java | 88 +++++ org/json/JSONObject.java | 739 +++++++++++++++++++-------------------- 2 files changed, 444 insertions(+), 383 deletions(-) diff --git a/org/json/JSONArray.java b/org/json/JSONArray.java index 762b077e6..78d7aedca 100644 --- a/org/json/JSONArray.java +++ b/org/json/JSONArray.java @@ -1052,6 +1052,94 @@ public JSONArray clone() { return this.stream().collect(new Collector<>()); } + public Optional getOptional(int index) { + try { + return Optional.of(this.get(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public > Optional> getOptionalEnum(Class clazz, int index) { + try { + return Optional.of(this.getEnum(clazz, index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalBoolean(int index) { + try { + return Optional.of(this.getBoolean(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalBigInteger(int index) { + try { + return Optional.of(this.getBigInteger(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalBigDecimal(int index) { + try { + return Optional.of(this.getBigDecimal(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalDouble(int index) { + try { + return Optional.of(this.getDouble(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalInt(int index) { + try { + return Optional.of(this.getInt(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalJSONArray(int index) { + try { + return Optional.of(this.getJSONArray(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalJSONObject(int index) { + try { + return Optional.of(this.getJSONObject(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalLong(int index) { + try { + return Optional.of(this.getLong(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalString(int index) { + try { + return Optional.of(this.getString(index)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + public class Collector implements java.util.stream.Collector { @Override public Supplier supplier() { diff --git a/org/json/JSONObject.java b/org/json/JSONObject.java index 8deed569e..d23b816b3 100644 --- a/org/json/JSONObject.java +++ b/org/json/JSONObject.java @@ -66,12 +66,12 @@ of this software and associated documentation files (the "Software"), to deal *

* The put methods add or replace values in an object. For * example, - * + *

*

  * myString = new JSONObject()
  *         .put("JSON", "Hello, World!").toString();
  * 
- * + *

* produces the string {"JSON": "Hello, World"}. *

* The texts produced by the toString methods strictly conform to @@ -115,10 +115,9 @@ protected final Object clone() { /** * A Null object is equal to the null value and to itself. * - * @param object - * An object to test for nullness. + * @param object An object to test for nullness. * @return true if the object parameter is the JSONObject.NULL object or - * null. + * null. */ @Override public boolean equals(Object object) { @@ -176,10 +175,8 @@ public JSONObject() { * strings is used to identify the keys that should be copied. Missing keys * are ignored. * - * @param jo - * A JSONObject. - * @param names - * An array of strings. + * @param jo A JSONObject. + * @param names An array of strings. */ public JSONObject(JSONObject jo, String[] names) { this(); @@ -194,11 +191,9 @@ public JSONObject(JSONObject jo, String[] names) { /** * Construct a JSONObject from a JSONTokener. * - * @param x - * A JSONTokener object containing the source string. - * @throws JSONException - * If there is a syntax error in the source string or a - * duplicated key. + * @param x A JSONTokener object containing the source string. + * @throws JSONException If there is a syntax error in the source string or a + * duplicated key. */ public JSONObject(JSONTokener x) throws JSONException { this(); @@ -208,16 +203,16 @@ public JSONObject(JSONTokener x) throws JSONException { if (x.nextClean() != '{') { throw x.syntaxError("A JSONObject text must begin with '{'"); } - for (;;) { + for (; ; ) { c = x.nextClean(); switch (c) { - case 0: - throw x.syntaxError("A JSONObject text must end with '}'"); - case '}': - return; - default: - x.back(); - key = x.nextValue().toString(); + case 0: + throw x.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + default: + x.back(); + key = x.nextValue().toString(); } // The key is followed by ':'. @@ -231,17 +226,17 @@ public JSONObject(JSONTokener x) throws JSONException { // Pairs are separated by ','. switch (x.nextClean()) { - case ';': - case ',': - if (x.nextClean() == '}') { + case ';': + case ',': + if (x.nextClean() == '}') { + return; + } + x.back(); + break; + case '}': return; - } - x.back(); - break; - case '}': - return; - default: - throw x.syntaxError("Expected a ',' or '}'"); + default: + throw x.syntaxError("Expected a ',' or '}'"); } } } @@ -249,14 +244,13 @@ public JSONObject(JSONTokener x) throws JSONException { /** * Construct a JSONObject from a Map. * - * @param map - * A map object that can be used to initialize the contents of + * @param map A map object that can be used to initialize the contents of * the JSONObject. */ public JSONObject(Map map) { this.map = new HashMap<>(); if (map != null) { - for (final Entry e : map.entrySet()) { + for (final Entry e : map.entrySet()) { final Object value = e.getValue(); if (value != null) { this.map.put(String.valueOf(e.getKey()), wrap(value)); @@ -272,19 +266,18 @@ public JSONObject(Map map) { * "is" followed by an uppercase letter, the method is invoked, * and a key and the value returned from the getter method are put into the * new JSONObject. - * + *

* The key is formed by removing the "get" or "is" * prefix. If the second remaining character is not upper case, then the * first character is converted to lower case. - * + *

* For example, if an object has a method named "getName", and * if the result of calling object.getName() is * "Larry Fine", then the JSONObject will contain * "name": "Larry Fine". * - * @param bean - * An object that has getter methods that should be used to make - * a JSONObject. + * @param bean An object that has getter methods that should be used to make + * a JSONObject. */ public JSONObject(Object bean) { this(); @@ -298,12 +291,10 @@ public JSONObject(Object bean) { * those keys in the object. If a key is not found or not visible, then it * will not be copied into the new JSONObject. * - * @param object - * An object that has fields that should be used to make a - * JSONObject. - * @param names - * An array of strings, the names of the fields to be obtained - * from the object. + * @param object An object that has fields that should be used to make a + * JSONObject. + * @param names An array of strings, the names of the fields to be obtained + * from the object. */ public JSONObject(Object object, String names[]) { this(); @@ -321,13 +312,11 @@ public JSONObject(Object object, String names[]) { * Construct a JSONObject from a source JSON text string. This is the most * commonly used JSONObject constructor. * - * @param source - * A string beginning with { (left - * brace) and ending with } - *  (right brace). - * @exception JSONException - * If there is a syntax error in the source string or a - * duplicated key. + * @param source A string beginning with { (left + * brace) and ending with } + *  (right brace). + * @throws JSONException If there is a syntax error in the source string or a + * duplicated key. */ public JSONObject(String source) throws JSONException { this(new JSONTokener(source)); @@ -336,17 +325,14 @@ public JSONObject(String source) throws JSONException { /** * Construct a JSONObject from a ResourceBundle. * - * @param baseName - * The ResourceBundle base name. - * @param locale - * The Locale to load the ResourceBundle for. - * @throws JSONException - * If any JSONExceptions are detected. + * @param baseName The ResourceBundle base name. + * @param locale The Locale to load the ResourceBundle for. + * @throws JSONException If any JSONExceptions are detected. */ public JSONObject(String baseName, Locale locale) throws JSONException { this(); ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, - Thread.currentThread().getContextClassLoader()); + Thread.currentThread().getContextClassLoader()); // Iterate through the keys in the bundle. @@ -382,26 +368,23 @@ public JSONObject(String baseName, Locale locale) throws JSONException { * is stored under the key to hold all of the accumulated values. If there * is already a JSONArray, then the new value is appended to it. In * contrast, the put method replaces the previous value. - * + *

* If only one value is accumulated that is not a JSONArray, then the result * will be the same as using put. But if multiple values are accumulated, * then the result will be like append. * - * @param key - * A key string. - * @param value - * An object to be accumulated under the key. + * @param key A key string. + * @param value An object to be accumulated under the key. * @return this. - * @throws JSONException - * If the value is an invalid number or if the key is null. + * @throws JSONException If the value is an invalid number or if the key is null. */ public JSONObject accumulate(String key, Object value) throws JSONException { testValidity(value); Object object = this.opt(key); if (object == null) { this.put(key, - value instanceof JSONArray ? new JSONArray().put(value) - : value); + value instanceof JSONArray ? new JSONArray().put(value) + : value); } else if (object instanceof JSONArray) { ((JSONArray) object).put(value); } else { @@ -416,14 +399,11 @@ public JSONObject accumulate(String key, Object value) throws JSONException { * JSONArray containing the value parameter. If the key was already * associated with a JSONArray, then the value parameter is appended to it. * - * @param key - * A key string. - * @param value - * An object to be accumulated under the key. + * @param key A key string. + * @param value An object to be accumulated under the key. * @return this. - * @throws JSONException - * If the key is null or if the current value associated with - * the key is not a JSONArray. + * @throws JSONException If the key is null or if the current value associated with + * the key is not a JSONArray. */ public JSONObject append(String key, Object value) throws JSONException { testValidity(value); @@ -434,7 +414,7 @@ public JSONObject append(String key, Object value) throws JSONException { this.put(key, ((JSONArray) object).put(value)); } else { throw new JSONException("JSONObject[" + key - + "] is not a JSONArray."); + + "] is not a JSONArray."); } return this; } @@ -443,8 +423,7 @@ public JSONObject append(String key, Object value) throws JSONException { * Produce a string from a double. The string "null" will be returned if the * number is not finite. * - * @param d - * A double. + * @param d A double. * @return A String. */ public static String doubleToString(double d) { @@ -456,7 +435,7 @@ public static String doubleToString(double d) { String string = Double.toString(d); if (string.indexOf('.') > 0 && string.indexOf('e') < 0 - && string.indexOf('E') < 0) { + && string.indexOf('E') < 0) { while (string.endsWith("0")) { string = string.substring(0, string.length() - 1); } @@ -470,11 +449,9 @@ public static String doubleToString(double d) { /** * Get the value object associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return The object associated with the key. - * @throws JSONException - * if the key is not found. + * @throws JSONException if the key is not found. */ public Object get(String key) throws JSONException { if (key == null) { @@ -488,26 +465,23 @@ public Object get(String key) throws JSONException { } /** - * Get the enum value associated with a key. - * - * @param clazz - * The type of enum to retrieve. - * @param key - * A key string. - * @return The enum value associated with the key - * @throws JSONException - * if the key is not found or if the value cannot be converted - * to an enum. - */ + * Get the enum value associated with a key. + * + * @param clazz The type of enum to retrieve. + * @param key A key string. + * @return The enum value associated with the key + * @throws JSONException if the key is not found or if the value cannot be converted + * to an enum. + */ public > E getEnum(Class clazz, String key) throws JSONException { E val = optEnum(clazz, key); - if(val==null) { + if (val == null) { // 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[" + quote(key) - + "] is not an enum of type " + quote(clazz.getSimpleName()) - + "."); + + "] is not an enum of type " + quote(clazz.getSimpleName()) + + "."); } return val; } @@ -515,37 +489,33 @@ public > E getEnum(Class clazz, String key) throws JSONExce /** * Get the boolean value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return The truth. - * @throws JSONException - * if the value is not a Boolean or the String "true" or - * "false". + * @throws JSONException if the value is not a Boolean or the String "true" or + * "false". */ public boolean getBoolean(String key) throws JSONException { Object object = this.get(key); if (object.equals(Boolean.FALSE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("false"))) { + || (object instanceof String && ((String) object) + .equalsIgnoreCase("false"))) { return false; } else if (object.equals(Boolean.TRUE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("true"))) { + || (object instanceof String && ((String) object) + .equalsIgnoreCase("true"))) { return true; } throw new JSONException("JSONObject[" + quote(key) - + "] is not a Boolean."); + + "] is not a Boolean."); } /** * Get the BigInteger value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return The numeric value. - * @throws JSONException - * if the key is not found or if the value cannot - * be converted to BigInteger. + * @throws JSONException if the key is not found or if the value cannot + * be converted to BigInteger. */ public BigInteger getBigInteger(String key) throws JSONException { Object object = this.get(key); @@ -553,19 +523,17 @@ public BigInteger getBigInteger(String key) throws JSONException { return new BigInteger(object.toString()); } catch (Exception e) { throw new JSONException("JSONObject[" + quote(key) - + "] could not be converted to BigInteger."); + + "] could not be converted to BigInteger."); } } /** * Get the BigDecimal value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return The numeric value. - * @throws JSONException - * if the key is not found or if the value - * cannot be converted to BigDecimal. + * @throws JSONException if the key is not found or if the value + * cannot be converted to BigDecimal. */ public BigDecimal getBigDecimal(String key) throws JSONException { Object object = this.get(key); @@ -573,60 +541,54 @@ public BigDecimal getBigDecimal(String key) throws JSONException { return new BigDecimal(object.toString()); } catch (Exception e) { throw new JSONException("JSONObject[" + quote(key) - + "] could not be converted to BigDecimal."); + + "] could not be converted to BigDecimal."); } } /** * Get the double value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @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. + * @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 double getDouble(String key) throws JSONException { Object object = this.get(key); try { return object instanceof Number ? ((Number) object).doubleValue() - : Double.parseDouble((String) object); + : Double.parseDouble((String) object); } catch (Exception e) { throw new JSONException("JSONObject[" + quote(key) - + "] is not a number."); + + "] is not a number."); } } /** * Get the int value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return The integer value. - * @throws JSONException - * if the key is not found or if the value cannot be converted - * to an integer. + * @throws JSONException if the key is not found or if the value cannot be converted + * to an integer. */ public int getInt(String key) throws JSONException { Object object = this.get(key); try { return object instanceof Number ? ((Number) object).intValue() - : Integer.parseInt((String) object); + : Integer.parseInt((String) object); } catch (Exception e) { throw new JSONException("JSONObject[" + quote(key) - + "] is not an int."); + + "] is not an int."); } } /** * Get the JSONArray value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return A JSONArray which is the value. - * @throws JSONException - * if the key is not found or if the value is not a JSONArray. + * @throws JSONException if the key is not found or if the value is not a JSONArray. */ public JSONArray getJSONArray(String key) throws JSONException { Object object = this.get(key); @@ -634,17 +596,15 @@ public JSONArray getJSONArray(String key) throws JSONException { return (JSONArray) object; } throw new JSONException("JSONObject[" + quote(key) - + "] is not a JSONArray."); + + "] is not a JSONArray."); } /** * Get the JSONObject value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return A JSONObject which is the value. - * @throws JSONException - * if the key is not found or if the value is not a JSONObject. + * @throws JSONException if the key is not found or if the value is not a JSONObject. */ public JSONObject getJSONObject(String key) throws JSONException { Object object = this.get(key); @@ -652,27 +612,25 @@ public JSONObject getJSONObject(String key) throws JSONException { return (JSONObject) object; } throw new JSONException("JSONObject[" + quote(key) - + "] is not a JSONObject."); + + "] is not a JSONObject."); } /** * Get the long value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return The long value. - * @throws JSONException - * if the key is not found or if the value cannot be converted - * to a long. + * @throws JSONException if the key is not found or if the value cannot be converted + * to a long. */ public long getLong(String key) throws JSONException { Object object = this.get(key); try { return object instanceof Number ? ((Number) object).longValue() - : Long.parseLong((String) object); + : Long.parseLong((String) object); } catch (Exception e) { throw new JSONException("JSONObject[" + quote(key) - + "] is not a long."); + + "] is not a long."); } } @@ -721,11 +679,9 @@ public static String[] getNames(Object object) { /** * Get the string associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return A string which is the value. - * @throws JSONException - * if there is no string value for the key. + * @throws JSONException if there is no string value for the key. */ public String getString(String key) throws JSONException { Object object = this.get(key); @@ -738,8 +694,7 @@ public String getString(String key) throws JSONException { /** * Determine if the JSONObject contains a specific key. * - * @param key - * A key string. + * @param key A key string. * @return true if the key exists in the JSONObject. */ public boolean has(String key) { @@ -751,21 +706,19 @@ public boolean has(String key) { * create one with a value of 1. If there is such a property, and if it is * an Integer, Long, Double, or Float, then add one to it. * - * @param key - * A key string. + * @param key A key string. * @return this. - * @throws JSONException - * If there is already a property with this name that is not an - * Integer, Long, Double, or Float. + * @throws JSONException If there is already a property with this name that is not an + * Integer, Long, Double, or Float. */ public JSONObject increment(String key) throws JSONException { Object value = this.opt(key); if (value == null) { this.put(key, 1); } else if (value instanceof BigInteger) { - this.put(key, ((BigInteger)value).add(BigInteger.ONE)); + this.put(key, ((BigInteger) value).add(BigInteger.ONE)); } else if (value instanceof BigDecimal) { - this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); + this.put(key, ((BigDecimal) value).add(BigDecimal.ONE)); } else if (value instanceof Integer) { this.put(key, (Integer) value + 1); } else if (value instanceof Long) { @@ -784,10 +737,9 @@ public JSONObject increment(String key) throws JSONException { * Determine if the value associated with the key is null or if there is no * value. * - * @param key - * A key string. + * @param key A key string. * @return true if there is no value associated with the key or if the value - * is the JSONObject.NULL object. + * is the JSONObject.NULL object. */ public boolean isNull(String key) { return JSONObject.NULL.equals(this.opt(key)); @@ -825,7 +777,7 @@ public int length() { * JSONObject. * * @return A JSONArray containing the key strings, or null if the JSONObject - * is empty. + * is empty. */ public JSONArray names() { JSONArray ja = new JSONArray(); @@ -839,11 +791,9 @@ public JSONArray names() { /** * Produce a string from a Number. * - * @param number - * A Number + * @param number A Number * @return A String. - * @throws JSONException - * If n is a non-finite number. + * @throws JSONException If n is a non-finite number. */ public static String numberToString(Number number) throws JSONException { if (number == null) { @@ -855,7 +805,7 @@ public static String numberToString(Number number) throws JSONException { String string = number.toString(); if (string.indexOf('.') > 0 && string.indexOf('e') < 0 - && string.indexOf('E') < 0) { + && string.indexOf('E') < 0) { while (string.endsWith("0")) { string = string.substring(0, string.length() - 1); } @@ -869,8 +819,7 @@ public static String numberToString(Number number) throws JSONException { /** * Get an optional value associated with a key. * - * @param key - * A key string. + * @param key A key string. * @return An object which is the value, or null if there is no value. */ public Object opt(String key) { @@ -879,11 +828,9 @@ public Object opt(String key) { /** * Get the enum value associated with a key. - * - * @param clazz - * The type of enum to retrieve. - * @param key - * A key string. + * + * @param clazz The type of enum to retrieve. + * @param key A key string. * @return The enum value associated with the key or null if not found */ public > E optEnum(Class clazz, String key) { @@ -892,15 +839,12 @@ public > E optEnum(Class clazz, String key) { /** * Get the enum value associated with a key. - * - * @param clazz - * The type of enum to retrieve. - * @param key - * A key string. - * @param defaultValue - * The default in case the value is not found + * + * @param clazz The type of enum to retrieve. + * @param key A key string. + * @param defaultValue The default in case the value is not found * @return The enum value associated with the key or defaultValue - * if the value is not found or cannot be assigned to clazz + * if the value is not found or cannot be assigned to clazz */ public > E optEnum(Class clazz, String key, E defaultValue) { try { @@ -926,8 +870,7 @@ public > E optEnum(Class clazz, String key, E defaultValue) * Get an optional boolean associated with a key. It returns false if there * is no such key, or if the value is not Boolean.TRUE or the String "true". * - * @param key - * A key string. + * @param key A key string. * @return The truth. */ public boolean optBoolean(String key) { @@ -939,10 +882,8 @@ public boolean optBoolean(String key) { * defaultValue if there is no such key, or if it is not a Boolean or the * String "true" or "false" (case insensitive). * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return The truth. */ public boolean optBoolean(String key, boolean defaultValue) { @@ -958,8 +899,7 @@ public boolean optBoolean(String key, boolean defaultValue) { * key or if its value is not a number. If the value is a string, an attempt * will be made to evaluate it as a number. * - * @param key - * A string which is the key. + * @param key A string which is the key. * @return An object which is the value. */ public double optDouble(String key) { @@ -971,10 +911,8 @@ public double optDouble(String key) { * there is no such key or if its value is not a number. If the value is a * string, an attempt will be made to evaluate it as a number. * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return An object which is the value. */ public BigInteger optBigInteger(String key, BigInteger defaultValue) { @@ -990,10 +928,8 @@ public BigInteger optBigInteger(String key, BigInteger defaultValue) { * there is no such key or if its value is not a number. If the value is a * string, an attempt will be made to evaluate it as a number. * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return An object which is the value. */ public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { @@ -1009,10 +945,8 @@ public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { * there is no such key or if its value is not a number. If the value is a * string, an attempt will be made to evaluate it as a number. * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return An object which is the value. */ public double optDouble(String key, double defaultValue) { @@ -1028,8 +962,7 @@ public double optDouble(String key, double defaultValue) { * 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. * - * @param key - * A key string. + * @param key A key string. * @return An object which is the value. */ public int optInt(String key) { @@ -1041,10 +974,8 @@ public int optInt(String key) { * 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. * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return An object which is the value. */ public int optInt(String key, int defaultValue) { @@ -1059,8 +990,7 @@ public int optInt(String key, int defaultValue) { * Get an optional JSONArray associated with a key. It returns null if there * is no such key, or if its value is not a JSONArray. * - * @param key - * A key string. + * @param key A key string. * @return A JSONArray which is the value. */ public JSONArray optJSONArray(String key) { @@ -1072,8 +1002,7 @@ public JSONArray optJSONArray(String key) { * Get an optional JSONObject associated with a key. It returns null if * there is no such key, or if its value is not a JSONObject. * - * @param key - * A key string. + * @param key A key string. * @return A JSONObject which is the value. */ public JSONObject optJSONObject(String key) { @@ -1086,8 +1015,7 @@ public JSONObject optJSONObject(String key) { * 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. * - * @param key - * A key string. + * @param key A key string. * @return An object which is the value. */ public long optLong(String key) { @@ -1099,10 +1027,8 @@ public long optLong(String key) { * 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. * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return An object which is the value. */ public long optLong(String key, long defaultValue) { @@ -1118,8 +1044,7 @@ public long optLong(String key, long defaultValue) { * if there is no such key. If the value is not a string and is not null, * then it is converted to a string. * - * @param key - * A key string. + * @param key A key string. * @return A string which is the value. */ public String optString(String key) { @@ -1130,10 +1055,8 @@ public String optString(String key) { * Get an optional string associated with a key. It returns the defaultValue * if there is no such key. * - * @param key - * A key string. - * @param defaultValue - * The default. + * @param key A key string. + * @param defaultValue The default. * @return A string which is the value. */ public String optString(String key, String defaultValue) { @@ -1149,7 +1072,7 @@ private void populateMap(Object bean) { boolean includeSuperClass = klass.getClassLoader() != null; Method[] methods = includeSuperClass ? klass.getMethods() : klass - .getDeclaredMethods(); + .getDeclaredMethods(); for (int i = 0; i < methods.length; i += 1) { try { Method method = methods[i]; @@ -1158,7 +1081,7 @@ private void populateMap(Object bean) { String key = ""; if (name.startsWith("get")) { if ("getClass".equals(name) - || "getDeclaringClass".equals(name)) { + || "getDeclaringClass".equals(name)) { key = ""; } else { key = name.substring(3); @@ -1167,13 +1090,13 @@ private void populateMap(Object bean) { key = name.substring(2); } if (key.length() > 0 - && Character.isUpperCase(key.charAt(0)) - && method.getParameterTypes().length == 0) { + && Character.isUpperCase(key.charAt(0)) + && method.getParameterTypes().length == 0) { if (key.length() == 1) { key = key.toLowerCase(); } else if (!Character.isUpperCase(key.charAt(1))) { key = key.substring(0, 1).toLowerCase() - + key.substring(1); + + key.substring(1); } Object result = method.invoke(bean, (Object[]) null); @@ -1190,13 +1113,10 @@ private void populateMap(Object bean) { /** * Put a key/boolean pair in the JSONObject. * - * @param key - * A key string. - * @param value - * A boolean which is the value. + * @param key A key string. + * @param value A boolean which is the value. * @return this. - * @throws JSONException - * If the key is null. + * @throws JSONException If the key is null. */ public JSONObject put(String key, boolean value) throws JSONException { this.put(key, value ? Boolean.TRUE : Boolean.FALSE); @@ -1207,10 +1127,8 @@ public JSONObject put(String key, boolean value) throws JSONException { * Put a key/value pair in the JSONObject, where the value will be a * JSONArray which is produced from a Collection. * - * @param key - * A key string. - * @param value - * A Collection value. + * @param key A key string. + * @param value A Collection value. * @return this. * @throws JSONException */ @@ -1222,13 +1140,10 @@ public JSONObject put(String key, Collection value) throws JSONException { /** * Put a key/double pair in the JSONObject. * - * @param key - * A key string. - * @param value - * A double which is the value. + * @param key A key string. + * @param value A double which is the value. * @return this. - * @throws JSONException - * If the key is null or if the number is invalid. + * @throws JSONException If the key is null or if the number is invalid. */ public JSONObject put(String key, double value) throws JSONException { this.put(key, new Double(value)); @@ -1238,13 +1153,10 @@ public JSONObject put(String key, double value) throws JSONException { /** * Put a key/int pair in the JSONObject. * - * @param key - * A key string. - * @param value - * An int which is the value. + * @param key A key string. + * @param value An int which is the value. * @return this. - * @throws JSONException - * If the key is null. + * @throws JSONException If the key is null. */ public JSONObject put(String key, int value) throws JSONException { this.put(key, new Integer(value)); @@ -1254,13 +1166,10 @@ public JSONObject put(String key, int value) throws JSONException { /** * Put a key/long pair in the JSONObject. * - * @param key - * A key string. - * @param value - * A long which is the value. + * @param key A key string. + * @param value A long which is the value. * @return this. - * @throws JSONException - * If the key is null. + * @throws JSONException If the key is null. */ public JSONObject put(String key, long value) throws JSONException { this.put(key, new Long(value)); @@ -1271,10 +1180,8 @@ public JSONObject put(String key, long value) throws JSONException { * Put a key/value pair in the JSONObject, where the value will be a * JSONObject which is produced from a Map. * - * @param key - * A key string. - * @param value - * A Map value. + * @param key A key string. + * @param value A Map value. * @return this. * @throws JSONException */ @@ -1287,15 +1194,12 @@ public JSONObject put(String key, Map value) throws JSONException { * Put a key/value pair in the JSONObject. If the value is null, then the * key will be removed from the JSONObject if it is present. * - * @param key - * A key string. - * @param value - * An object which is the value. It should be of one of these - * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, - * String, or the JSONObject.NULL object. + * @param key A key string. + * @param value An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. * @return this. - * @throws JSONException - * If the value is non-finite number or if the key is null. + * @throws JSONException If the value is non-finite number or if the key is null. */ public JSONObject put(String key, Object value) throws JSONException { if (key == null) { @@ -1315,11 +1219,10 @@ public JSONObject put(String key, Object value) throws JSONException { * are both non-null, and only if there is not already a member with that * name. * - * @param key string + * @param key string * @param value object * @return this. - * @throws JSONException - * if the key is a duplicate + * @throws JSONException if the key is a duplicate */ public JSONObject putOnce(String key, Object value) throws JSONException { if (key != null && value != null) { @@ -1335,15 +1238,12 @@ public JSONObject putOnce(String key, Object value) throws JSONException { * Put a key/value pair in the JSONObject, but only if the key and the value * are both non-null. * - * @param key - * A key string. - * @param value - * An object which is the value. It should be of one of these - * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, - * String, or the JSONObject.NULL object. + * @param key A key string. + * @param value An object which is the value. It should be of one of these + * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, + * String, or the JSONObject.NULL object. * @return this. - * @throws JSONException - * If the value is a non-finite number. + * @throws JSONException If the value is a non-finite number. */ public JSONObject putOpt(String key, Object value) throws JSONException { if (key != null && value != null) { @@ -1358,8 +1258,7 @@ public JSONObject putOpt(String key, Object value) throws JSONException { * allowing JSON text to be delivered in HTML. In JSON text, a string cannot * contain a control character or an unescaped quote or backslash. * - * @param string - * A String + * @param string A String * @return A String correctly formatted for insertion in a JSON text. */ public static String quote(String string) { @@ -1391,42 +1290,42 @@ public static Writer quote(String string, Writer w) throws IOException { b = c; c = string.charAt(i); switch (c) { - case '\\': - case '"': - w.write('\\'); - w.write(c); - break; - case '/': - if (b == '<') { + case '\\': + case '"': w.write('\\'); - } - w.write(c); - break; - case '\b': - w.write("\\b"); - break; - case '\t': - w.write("\\t"); - break; - case '\n': - w.write("\\n"); - break; - case '\f': - w.write("\\f"); - break; - case '\r': - w.write("\\r"); - break; - default: - if (c < ' ' || (c >= '\u0080' && c < '\u00a0') - || (c >= '\u2000' && c < '\u2100')) { - w.write("\\u"); - hhhh = Integer.toHexString(c); - w.write("0000", 0, 4 - hhhh.length()); - w.write(hhhh); - } else { w.write(c); - } + break; + case '/': + if (b == '<') { + w.write('\\'); + } + w.write(c); + break; + case '\b': + w.write("\\b"); + break; + case '\t': + w.write("\\t"); + break; + case '\n': + w.write("\\n"); + break; + case '\f': + w.write("\\f"); + break; + case '\r': + w.write("\\r"); + break; + default: + if (c < ' ' || (c >= '\u0080' && c < '\u00a0') + || (c >= '\u2000' && c < '\u2100')) { + w.write("\\u"); + hhhh = Integer.toHexString(c); + w.write("0000", 0, 4 - hhhh.length()); + w.write(hhhh); + } else { + w.write(c); + } } } w.write('"'); @@ -1436,10 +1335,9 @@ public static Writer quote(String string, Writer w) throws IOException { /** * Remove a name and its value, if present. * - * @param key - * The name to be removed. + * @param key The name to be removed. * @return The value that was associated with the name, or null if there was - * no value. + * no value. */ public Object remove(String key) { return this.map.remove(key); @@ -1459,20 +1357,20 @@ public boolean similar(Object other) { return false; } Set set = this.keySet(); - if (!set.equals(((JSONObject)other).keySet())) { + if (!set.equals(((JSONObject) other).keySet())) { return false; } Iterator iterator = set.iterator(); while (iterator.hasNext()) { String name = iterator.next(); Object valueThis = this.get(name); - Object valueOther = ((JSONObject)other).get(name); + Object valueOther = ((JSONObject) other).get(name); if (valueThis instanceof JSONObject) { - if (!((JSONObject)valueThis).similar(valueOther)) { + if (!((JSONObject) valueThis).similar(valueOther)) { return false; } } else if (valueThis instanceof JSONArray) { - if (!((JSONArray)valueThis).similar(valueOther)) { + if (!((JSONArray) valueThis).similar(valueOther)) { return false; } } else if (!valueThis.equals(valueOther)) { @@ -1489,8 +1387,7 @@ public boolean similar(Object other) { * Try to convert a string into a number, boolean, or null. If the string * can't be converted, return the string. * - * @param string - * A String. + * @param string A String. * @return A simple JSON value. */ public static Object stringToValue(String string) { @@ -1516,8 +1413,8 @@ public static Object stringToValue(String string) { if ((initial >= '0' && initial <= '9') || initial == '-') { try { if (string.indexOf('.') > -1 || string.indexOf('e') > -1 - || string.indexOf('E') > -1 - || "-0".equals(string)) { + || string.indexOf('E') > -1 + || "-0".equals(string)) { Double d = Double.valueOf(string); if (!d.isInfinite() && !d.isNaN()) { return d; @@ -1540,22 +1437,20 @@ public static Object stringToValue(String string) { /** * Throw an exception if the object is a NaN or infinite number. * - * @param o - * The object to test. - * @throws JSONException - * If o is a non-finite number. + * @param o The object to test. + * @throws JSONException If o is a non-finite number. */ public static void testValidity(Object o) throws JSONException { if (o != null) { if (o instanceof Double) { if (((Double) o).isInfinite() || ((Double) o).isNaN()) { throw new JSONException( - "JSON does not allow non-finite numbers."); + "JSON does not allow non-finite numbers."); } } else if (o instanceof Float) { if (((Float) o).isInfinite() || ((Float) o).isNaN()) { throw new JSONException( - "JSON does not allow non-finite numbers."); + "JSON does not allow non-finite numbers."); } } } @@ -1565,12 +1460,10 @@ public static void testValidity(Object o) throws JSONException { * Produce a JSONArray containing the values of the members of this * JSONObject. * - * @param names - * A JSONArray containing a list of key strings. This determines - * the sequence of the values in the result. + * @param names A JSONArray containing a list of key strings. This determines + * the sequence of the values in the result. * @return A JSONArray of values. - * @throws JSONException - * If any of the values are non-finite numbers. + * @throws JSONException If any of the values are non-finite numbers. */ public JSONArray toJSONArray(JSONArray names) throws JSONException { if (names == null || names.length() == 0) { @@ -1591,9 +1484,9 @@ public JSONArray toJSONArray(JSONArray names) throws JSONException { * Warning: This method assumes that the data structure is acyclical. * * @return a printable, displayable, portable, transmittable representation - * of the object, beginning with { (left - * brace) and ending with } (right - * brace). + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). */ public String toString() { try { @@ -1608,14 +1501,12 @@ public String toString() { *

* Warning: This method assumes that the data structure is acyclical. * - * @param indentFactor - * The number of spaces to add to each level of indentation. + * @param indentFactor The number of spaces to add to each level of indentation. * @return a printable, displayable, portable, transmittable representation - * of the object, beginning with { (left - * brace) and ending with } (right - * brace). - * @throws JSONException - * If the object contains an invalid number. + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException If the object contains an invalid number. */ public String toString(int indentFactor) throws JSONException { StringWriter w = new StringWriter(); @@ -1635,18 +1526,16 @@ public String toString(int indentFactor) throws JSONException { * 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. - * + *

*

* Warning: This method assumes that the data structure is acyclical. * - * @param value - * The value to be serialized. + * @param value The value to be serialized. * @return a printable, displayable, transmittable representation of the - * object, beginning with { (left - * brace) and ending with } (right - * brace). - * @throws JSONException - * If the value is or contains an invalid number. + * object, beginning with { (left + * brace) and ending with } (right + * brace). + * @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)) { @@ -1668,7 +1557,7 @@ public static String valueToString(Object value) throws JSONException { return numberToString((Number) value); } if (value instanceof Boolean || value instanceof JSONObject - || value instanceof JSONArray) { + || value instanceof JSONArray) { return value.toString(); } if (value instanceof Map) { @@ -1693,8 +1582,7 @@ public static String valueToString(Object value) throws JSONException { * one of the java packages, turn it into a string. And if it doesn't, try * to wrap it in a JSONObject. If the wrapping fails, then null is returned. * - * @param object - * The object to wrap + * @param object The object to wrap * @return The wrapped value */ public static Object wrap(Object object) { @@ -1703,13 +1591,13 @@ public static Object wrap(Object object) { return NULL; } if (object instanceof JSONObject || object instanceof JSONArray - || NULL.equals(object) || object instanceof JSONString - || object instanceof Byte || object instanceof Character - || object instanceof Short || object instanceof Integer - || object instanceof Long || object instanceof Boolean - || object instanceof Float || object instanceof Double - || object instanceof String || object instanceof BigInteger - || object instanceof BigDecimal) { + || NULL.equals(object) || object instanceof JSONString + || object instanceof Byte || object instanceof Character + || object instanceof Short || object instanceof Integer + || object instanceof Long || object instanceof Boolean + || object instanceof Float || object instanceof Double + || object instanceof String || object instanceof BigInteger + || object instanceof BigDecimal) { return object; } @@ -1726,10 +1614,10 @@ public static Object wrap(Object object) { } Package objectPackage = object.getClass().getPackage(); String objectPackageName = objectPackage != null ? objectPackage - .getName() : ""; + .getName() : ""; if (objectPackageName.startsWith("java.") - || objectPackageName.startsWith("javax.") - || object.getClass().getClassLoader() == null) { + || objectPackageName.startsWith("javax.") + || object.getClass().getClassLoader() == null) { return object.toString(); } return new JSONObject(object); @@ -1752,7 +1640,7 @@ public Writer write(Writer writer) throws JSONException { } static final Writer writeValue(Writer writer, Object value, - int indentFactor, int indent) throws JSONException, IOException { + int indentFactor, int indent) throws JSONException, IOException { if (value == null || value.equals(null)) { writer.write("null"); } else if (value instanceof JSONObject) { @@ -1797,17 +1685,14 @@ static final void indent(Writer writer, int indent) throws IOException { *

* Warning: This method assumes that the data structure is acyclical. * - * @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. + * @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. * @return The writer. * @throws JSONException */ public Writer write(Writer writer, int indentFactor, int indent) - throws JSONException { + throws JSONException { try { boolean commanate = false; final int length = this.length(); @@ -1889,6 +1774,94 @@ public JSONObject clone() { return this.map.entrySet().stream().collect(new Collector<>()); } + public Optional getOptional(String key) { + try { + return Optional.of(this.get(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public > Optional> getOptionalEnum(Class clazz, String key) { + try { + return Optional.of(this.getEnum(clazz, key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalBoolean(String key) { + try { + return Optional.of(this.getBoolean(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalBigInteger(String key) { + try { + return Optional.of(this.getBigInteger(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalBigDecimal(String key) { + try { + return Optional.of(this.getBigDecimal(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalDouble(String key) { + try { + return Optional.of(this.getDouble(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalInt(String key) { + try { + return Optional.of(this.getInt(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalJSONArray(String key) { + try { + return Optional.of(this.getJSONArray(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalJSONObject(String key) { + try { + return Optional.of(this.getJSONObject(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalLong(String key) { + try { + return Optional.of(this.getLong(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + + public Optional getOptionalString(String key) { + try { + return Optional.of(this.getString(key)); + } catch (JSONException | NullPointerException e) { + return Optional.empty(); + } + } + public class Collector implements java.util.stream.Collector, JSONObject, JSONObject> { @Override public Supplier supplier() {