11package org .json ;
22
33import java .io .IOException ;
4+ import java .math .BigDecimal ;
5+ import java .util .Collection ;
6+ import java .util .Map ;
47
58/*
69Copyright (c) 2006 JSON.org
@@ -117,6 +120,9 @@ private JSONWriter append(String string) throws JSONException {
117120 }
118121 this .writer .append (string );
119122 } catch (IOException e ) {
123+ // Android as of API 25 does not support this exception constructor
124+ // however we won't worry about it. If an exception is happening here
125+ // it will just throw a "Method not found" exception instead.
120126 throw new JSONException (e );
121127 }
122128 if (this .mode == 'o' ) {
@@ -164,6 +170,9 @@ private JSONWriter end(char m, char c) throws JSONException {
164170 try {
165171 this .writer .append (c );
166172 } catch (IOException e ) {
173+ // Android as of API 25 does not support this exception constructor
174+ // however we won't worry about it. If an exception is happening here
175+ // it will just throw a "Method not found" exception instead.
167176 throw new JSONException (e );
168177 }
169178 this .comma = true ;
@@ -204,7 +213,12 @@ public JSONWriter key(String string) throws JSONException {
204213 }
205214 if (this .mode == 'k' ) {
206215 try {
207- this .stack [this .top - 1 ].putOnce (string , Boolean .TRUE );
216+ JSONObject topObject = this .stack [this .top - 1 ];
217+ // don't use the built in putOnce method to maintain Android support
218+ if (topObject .has (string )) {
219+ throw new JSONException ("Duplicate key \" " + string + "\" " );
220+ }
221+ topObject .put (string , true );
208222 if (this .comma ) {
209223 this .writer .append (',' );
210224 }
@@ -214,6 +228,9 @@ public JSONWriter key(String string) throws JSONException {
214228 this .mode = 'o' ;
215229 return this ;
216230 } catch (IOException e ) {
231+ // Android as of API 25 does not support this exception constructor
232+ // however we won't worry about it. If an exception is happening here
233+ // it will just throw a "Method not found" exception instead.
217234 throw new JSONException (e );
218235 }
219236 }
@@ -280,6 +297,81 @@ private void push(JSONObject jo) throws JSONException {
280297 this .top += 1 ;
281298 }
282299
300+ /**
301+ * Make a JSON text of an Object value. If the object has an
302+ * value.toJSONString() method, then that method will be used to produce the
303+ * JSON text. The method is required to produce a strictly conforming text.
304+ * If the object does not contain a toJSONString method (which is the most
305+ * common case), then a text will be produced by other means. If the value
306+ * is an array or Collection, then a JSONArray will be made from it and its
307+ * toJSONString method will be called. If the value is a MAP, then a
308+ * JSONObject will be made from it and its toJSONString method will be
309+ * called. Otherwise, the value's toString method will be called, and the
310+ * result will be quoted.
311+ *
312+ * <p>
313+ * Warning: This method assumes that the data structure is acyclical.
314+ *
315+ * @param value
316+ * The value to be serialized.
317+ * @return a printable, displayable, transmittable representation of the
318+ * object, beginning with <code>{</code> <small>(left
319+ * brace)</small> and ending with <code>}</code> <small>(right
320+ * brace)</small>.
321+ * @throws JSONException
322+ * If the value is or contains an invalid number.
323+ */
324+ public static String valueToString (Object value ) throws JSONException {
325+ if (value == null || value .equals (null )) {
326+ return "null" ;
327+ }
328+ if (value instanceof JSONString ) {
329+ Object object ;
330+ try {
331+ object = ((JSONString ) value ).toJSONString ();
332+ } catch (Exception e ) {
333+ throw new JSONException (e );
334+ }
335+ if (object instanceof String ) {
336+ return (String ) object ;
337+ }
338+ throw new JSONException ("Bad value from toJSONString: " + object );
339+ }
340+ if (value instanceof Number ) {
341+ // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
342+ final String numberAsString = JSONObject .numberToString ((Number ) value );
343+ try {
344+ // Use the BigDecimal constructor for it's parser to validate the format.
345+ @ SuppressWarnings ("unused" )
346+ BigDecimal unused = new BigDecimal (numberAsString );
347+ // Close enough to a JSON number that we will return it unquoted
348+ return numberAsString ;
349+ } catch (NumberFormatException ex ){
350+ // The Number value is not a valid JSON number.
351+ // Instead we will quote it as a string
352+ return JSONObject .quote (numberAsString );
353+ }
354+ }
355+ if (value instanceof Boolean || value instanceof JSONObject
356+ || value instanceof JSONArray ) {
357+ return value .toString ();
358+ }
359+ if (value instanceof Map ) {
360+ Map <?, ?> map = (Map <?, ?>) value ;
361+ return new JSONObject (map ).toString ();
362+ }
363+ if (value instanceof Collection ) {
364+ Collection <?> coll = (Collection <?>) value ;
365+ return new JSONArray (coll ).toString ();
366+ }
367+ if (value .getClass ().isArray ()) {
368+ return new JSONArray (value ).toString ();
369+ }
370+ if (value instanceof Enum <?>){
371+ return JSONObject .quote (((Enum <?>)value ).name ());
372+ }
373+ return JSONObject .quote (value .toString ());
374+ }
283375
284376 /**
285377 * Append either the value <code>true</code> or the value
@@ -321,6 +413,6 @@ public JSONWriter value(long l) throws JSONException {
321413 * @throws JSONException If the value is out of sequence.
322414 */
323415 public JSONWriter value (Object object ) throws JSONException {
324- return this .append (JSONObject . valueToString (object ));
416+ return this .append (valueToString (object ));
325417 }
326418}
0 commit comments