diff --git a/JSONArray.java b/JSONArray.java index fbc1a0f..537abb1 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -180,10 +180,16 @@ public class JSONArray implements Iterable { } /** - * Construct a JSONArray from an array + * Construct a JSONArray from an array. + * + * @param array + * Array. If the parameter passed is null, or not an array, an + * exception will be thrown. * * @throws JSONException - * If not an array or if an array value is non-finite number. + * If not an array or if an array value is non-finite number. + * @throws NullPointerException + * Thrown if the array parameter is null. */ public JSONArray(Object array) throws JSONException { this(); @@ -257,13 +263,7 @@ public class JSONArray implements Iterable { * 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); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index + "] is not a number.", e); - } + return this.getNumber(index).doubleValue(); } /** @@ -277,14 +277,7 @@ public class JSONArray implements Iterable { * object and cannot be converted to a number. */ public float getFloat(int index) throws JSONException { - Object object = this.get(index); - try { - return object instanceof Number ? ((Number) object).floatValue() - : Float.parseFloat(object.toString()); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index - + "] is not a number.", e); - } + return this.getNumber(index).floatValue(); } /** @@ -310,17 +303,19 @@ public class JSONArray implements Iterable { } /** - * 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 + * Enum Type + * @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) { @@ -334,7 +329,10 @@ public class JSONArray implements Iterable { } /** - * Get the BigDecimal value associated with an index. + * Get the BigDecimal value associated with an index. If the value is float + * or double, the the {@link BigDecimal#BigDecimal(double)} constructor + * will be used. See notes on the constructor for conversion issues that + * may arise. * * @param index * The index must be between 0 and length() - 1. @@ -345,12 +343,12 @@ public class JSONArray implements Iterable { */ public BigDecimal getBigDecimal (int index) throws JSONException { Object object = this.get(index); - try { - return new BigDecimal(object.toString()); - } catch (Exception e) { + BigDecimal val = JSONObject.objectToBigDecimal(object, null); + if(val == null) { throw new JSONException("JSONArray[" + index + - "] could not convert to BigDecimal.", e); + "] could not convert to BigDecimal ("+ object + ")."); } + return val; } /** @@ -365,12 +363,12 @@ public class JSONArray implements Iterable { */ public BigInteger getBigInteger (int index) throws JSONException { Object object = this.get(index); - try { - return new BigInteger(object.toString()); - } catch (Exception e) { + BigInteger val = JSONObject.objectToBigInteger(object, null); + if(val == null) { throw new JSONException("JSONArray[" + index + - "] could not convert to BigInteger.", e); + "] could not convert to BigDecimal ("+ object + ")."); } + return val; } /** @@ -383,13 +381,7 @@ public class JSONArray implements Iterable { * 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); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index + "] is not a number.", e); - } + return this.getNumber(index).intValue(); } /** @@ -439,13 +431,7 @@ public class JSONArray implements Iterable { * 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); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index + "] is not a number.", e); - } + return this.getNumber(index).longValue(); } /** @@ -489,13 +475,16 @@ public class JSONArray implements Iterable { */ public String join(String separator) throws JSONException { int len = this.length(); - StringBuilder sb = new StringBuilder(); + if (len == 0) { + return ""; + } + + StringBuilder sb = new StringBuilder( + JSONObject.valueToString(this.myArrayList.get(0))); - for (int i = 0; i < len; i += 1) { - if (i > 0) { - sb.append(separator); - } - sb.append(JSONObject.valueToString(this.myArrayList.get(i))); + for (int i = 1; i < len; i++) { + sb.append(separator) + .append(JSONObject.valueToString(this.myArrayList.get(i))); } return sb.toString(); } @@ -578,21 +567,15 @@ public class JSONArray implements Iterable { * @return The value. */ public double optDouble(int index, double defaultValue) { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { + final Number val = this.optNumber(index, null); + if (val == null) { return defaultValue; } - if (val instanceof Number){ - return ((Number) val).doubleValue(); - } - if (val instanceof String) { - try { - return Double.parseDouble((String) val); - } catch (Exception e) { - return defaultValue; - } - } - return defaultValue; + final double doubleValue = val.doubleValue(); + // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) { + // return defaultValue; + // } + return doubleValue; } /** @@ -620,21 +603,15 @@ public class JSONArray implements Iterable { * @return The value. */ public float optFloat(int index, float defaultValue) { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { + final Number val = this.optNumber(index, null); + if (val == null) { return defaultValue; } - if (val instanceof Number){ - return ((Number) val).floatValue(); - } - if (val instanceof String) { - try { - return Float.parseFloat((String) val); - } catch (Exception e) { - return defaultValue; - } - } - return defaultValue; + final float floatValue = val.floatValue(); + // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) { + // return floatValue; + // } + return floatValue; } /** @@ -662,27 +639,18 @@ public class JSONArray implements Iterable { * @return The value. */ public int optInt(int index, int defaultValue) { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { + final Number val = this.optNumber(index, null); + if (val == null) { return defaultValue; } - if (val instanceof Number){ - return ((Number) val).intValue(); - } - - if (val instanceof String) { - try { - return new BigDecimal(val.toString()).intValue(); - } catch (Exception e) { - return defaultValue; - } - } - return defaultValue; + return val.intValue(); } /** * Get the enum value associated with a key. * + * @param + * Enum Type * @param clazz * The type of enum to retrieve. * @param index @@ -696,6 +664,8 @@ public class JSONArray implements Iterable { /** * Get the enum value associated with a key. * + * @param + * Enum Type * @param clazz * The type of enum to retrieve. * @param index @@ -725,7 +695,6 @@ public class JSONArray implements Iterable { } } - /** * Get the optional BigInteger value associated with an index. The * defaultValue is returned if there is no value for the index, or if the @@ -739,37 +708,16 @@ public class JSONArray implements Iterable { */ public BigInteger optBigInteger(int index, BigInteger defaultValue) { Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { - return defaultValue; - } - if (val instanceof BigInteger){ - return (BigInteger) val; - } - if (val instanceof BigDecimal){ - return ((BigDecimal) val).toBigInteger(); - } - if (val instanceof Double || val instanceof Float){ - return new BigDecimal(((Number) val).doubleValue()).toBigInteger(); - } - if (val instanceof Long || val instanceof Integer - || val instanceof Short || val instanceof Byte){ - return BigInteger.valueOf(((Number) val).longValue()); - } - try { - final String valStr = val.toString(); - if(JSONObject.isDecimalNotation(valStr)) { - return new BigDecimal(valStr).toBigInteger(); - } - return new BigInteger(valStr); - } catch (Exception e) { - return defaultValue; - } + return JSONObject.objectToBigInteger(val, defaultValue); } /** * Get the optional BigDecimal value associated with an index. The * defaultValue is returned if there is no value for the index, or if the - * value is not a number and cannot be converted to a number. + * value is not a number and cannot be converted to a number. If the value + * is float or double, the the {@link BigDecimal#BigDecimal(double)} + * constructor will be used. See notes on the constructor for conversion + * issues that may arise. * * @param index * The index must be between 0 and length() - 1. @@ -779,27 +727,7 @@ public class JSONArray implements Iterable { */ public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { - return defaultValue; - } - if (val instanceof BigDecimal){ - return (BigDecimal) val; - } - if (val instanceof BigInteger){ - return new BigDecimal((BigInteger) val); - } - if (val instanceof Double || val instanceof Float){ - return new BigDecimal(((Number) val).doubleValue()); - } - if (val instanceof Long || val instanceof Integer - || val instanceof Short || val instanceof Byte){ - return new BigDecimal(((Number) val).longValue()); - } - try { - return new BigDecimal(val.toString()); - } catch (Exception e) { - return defaultValue; - } + return JSONObject.objectToBigDecimal(val, defaultValue); } /** @@ -854,22 +782,11 @@ public class JSONArray implements Iterable { * @return The value. */ public long optLong(int index, long defaultValue) { - Object val = this.opt(index); - if (JSONObject.NULL.equals(val)) { + final Number val = this.optNumber(index, null); + if (val == null) { return defaultValue; } - if (val instanceof Number){ - return ((Number) val).longValue(); - } - - if (val instanceof String) { - try { - return new BigDecimal(val.toString()).longValue(); - } catch (Exception e) { - return defaultValue; - } - } - return defaultValue; + return val.longValue(); } /** @@ -1236,8 +1153,8 @@ public class JSONArray implements Iterable { } /** - * Uses a uaer initialized JSONPointer and tries to - * match it to an item whithin this JSONArray. For example, given a + * Uses a user initialized JSONPointer and tries to + * match it to an item within this JSONArray. For example, given a * JSONArray initialized with this document: *
      * [
@@ -1535,7 +1452,7 @@ public class JSONArray implements Iterable {
      * @return true if JSONArray is empty, otherwise false.
      */
     public boolean isEmpty() {
-        return myArrayList.isEmpty();
+        return this.myArrayList.isEmpty();
     }
 
 }
diff --git a/JSONObject.java b/JSONObject.java
index 8deb6ba..a1ed490 100644
--- a/JSONObject.java
+++ b/JSONObject.java
@@ -45,6 +45,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.ResourceBundle;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 /**
  * A JSONObject is an unordered collection of name/value pairs. Its external
@@ -150,6 +151,12 @@ public class JSONObject {
             return "null";
         }
     }
+    
+    /**
+     *  Regular Expression Pattern that matches JSON Numbers. This is primarily used for
+     *  output to guarantee that we are always writing valid JSON. 
+     */
+    static final Pattern NUMBER_PATTERN = Pattern.compile("-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?");
 
     /**
      * The map where the JSONObject's properties are kept.
@@ -569,17 +576,19 @@ public class JSONObject {
     }
 
     /**
-    * 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 
+     *            Enum Type
+     * @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) {
@@ -630,16 +639,19 @@ public class JSONObject {
      */
     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.", e);
+        BigInteger ret = objectToBigInteger(object, null);
+        if (ret != null) {
+            return ret;
         }
+        throw new JSONException("JSONObject[" + quote(key)
+                + "] could not be converted to BigInteger (" + object + ").");
     }
 
     /**
-     * Get the BigDecimal value associated with a key.
+     * Get the BigDecimal value associated with a key. If the value is float or
+     * double, the the {@link BigDecimal#BigDecimal(double)} constructor will
+     * be used. See notes on the constructor for conversion issues that may
+     * arise.
      *
      * @param key
      *            A key string.
@@ -650,15 +662,12 @@ public class JSONObject {
      */
     public BigDecimal getBigDecimal(String key) throws JSONException {
         Object object = this.get(key);
-        if (object instanceof BigDecimal) {
-            return (BigDecimal)object;
-        }
-        try {
-            return new BigDecimal(object.toString());
-        } catch (Exception e) {
-            throw new JSONException("JSONObject[" + quote(key)
-                    + "] could not be converted to BigDecimal.", e);
+        BigDecimal ret = objectToBigDecimal(object, null);
+        if (ret != null) {
+            return ret;
         }
+        throw new JSONException("JSONObject[" + quote(key)
+                + "] could not be converted to BigDecimal (" + object + ").");
     }
 
     /**
@@ -672,14 +681,7 @@ public class JSONObject {
      *             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(object.toString());
-        } catch (Exception e) {
-            throw new JSONException("JSONObject[" + quote(key)
-                    + "] is not a number.", e);
-        }
+        return this.getNumber(key).doubleValue();
     }
 
     /**
@@ -693,14 +695,7 @@ public class JSONObject {
      *             object and cannot be converted to a number.
      */
     public float getFloat(String key) throws JSONException {
-        Object object = this.get(key);
-        try {
-            return object instanceof Number ? ((Number) object).floatValue()
-                    : Float.parseFloat(object.toString());
-        } catch (Exception e) {
-            throw new JSONException("JSONObject[" + quote(key)
-                    + "] is not a number.", e);
-        }
+        return this.getNumber(key).floatValue();
     }
 
     /**
@@ -737,14 +732,7 @@ public class JSONObject {
      *             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);
-        } catch (Exception e) {
-            throw new JSONException("JSONObject[" + quote(key)
-                    + "] is not an int.", e);
-        }
+        return this.getNumber(key).intValue();
     }
 
     /**
@@ -794,19 +782,14 @@ public class JSONObject {
      *             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);
-        } catch (Exception e) {
-            throw new JSONException("JSONObject[" + quote(key)
-                    + "] is not a long.", e);
-        }
+        return this.getNumber(key).longValue();
     }
 
     /**
      * Get an array of field names from a JSONObject.
      *
+     * @param jo
+     *            JSON object
      * @return An array of field names, or null if there are no names.
      */
     public static String[] getNames(JSONObject jo) {
@@ -817,8 +800,10 @@ public class JSONObject {
     }
 
     /**
-     * Get an array of field names from an Object.
+     * Get an array of public field names from an Object.
      *
+     * @param object
+     *            object to read
      * @return An array of field names, or null if there are no names.
      */
     public static String[] getNames(Object object) {
@@ -968,7 +953,7 @@ public class JSONObject {
      * @return true if JSONObject is empty, otherwise false.
      */
     public boolean isEmpty() {
-        return map.isEmpty();
+        return this.map.isEmpty();
     }
 
     /**
@@ -1029,6 +1014,8 @@ public class JSONObject {
     /**
      * Get the enum value associated with a key.
      * 
+     * @param 
+     *            Enum Type
      * @param clazz
      *            The type of enum to retrieve.
      * @param key
@@ -1042,6 +1029,8 @@ public class JSONObject {
     /**
      * Get the enum value associated with a key.
      * 
+     * @param 
+     *            Enum Type
      * @param clazz
      *            The type of enum to retrieve.
      * @param key
@@ -1113,7 +1102,10 @@ public class JSONObject {
     /**
      * 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.
+     * string, an attempt will be made to evaluate it as a number. If the value
+     * is float or double, then the {@link BigDecimal#BigDecimal(double)}
+     * constructor will be used. See notes on the constructor for conversion
+     * issues that may arise.
      *
      * @param key
      *            A key string.
@@ -1123,6 +1115,16 @@ public class JSONObject {
      */
     public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
         Object val = this.opt(key);
+        return objectToBigDecimal(val, defaultValue);
+    }
+
+    /**
+     * @param val value to convert
+     * @param defaultValue default value to return is the conversion doesn't work or is null.
+     * @return BigDecimal conversion of the original value, or the defaultValue if unable
+     *          to convert. 
+     */
+    static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) {
         if (NULL.equals(val)) {
             return defaultValue;
         }
@@ -1133,6 +1135,10 @@ public class JSONObject {
             return new BigDecimal((BigInteger) val);
         }
         if (val instanceof Double || val instanceof Float){
+            final double d = ((Number) val).doubleValue();
+            if(Double.isNaN(d)) {
+                return defaultValue;
+            }
             return new BigDecimal(((Number) val).doubleValue());
         }
         if (val instanceof Long || val instanceof Integer
@@ -1160,6 +1166,16 @@ public class JSONObject {
      */
     public BigInteger optBigInteger(String key, BigInteger defaultValue) {
         Object val = this.opt(key);
+        return objectToBigInteger(val, defaultValue);
+    }
+
+    /**
+     * @param val value to convert
+     * @param defaultValue default value to return is the conversion doesn't work or is null.
+     * @return BigInteger conversion of the original value, or the defaultValue if unable
+     *          to convert. 
+     */
+    static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) {
         if (NULL.equals(val)) {
             return defaultValue;
         }
@@ -1170,7 +1186,11 @@ public class JSONObject {
             return ((BigDecimal) val).toBigInteger();
         }
         if (val instanceof Double || val instanceof Float){
-            return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
+            final double d = ((Number) val).doubleValue();
+            if(Double.isNaN(d)) {
+                return defaultValue;
+            }
+            return new BigDecimal(d).toBigInteger();
         }
         if (val instanceof Long || val instanceof Integer
                 || val instanceof Short || val instanceof Byte){
@@ -1218,21 +1238,15 @@ public class JSONObject {
      * @return An object which is the value.
      */
     public double optDouble(String key, double defaultValue) {
-        Object val = this.opt(key);
-        if (NULL.equals(val)) {
+        Number val = this.optNumber(key);
+        if (val == null) {
             return defaultValue;
         }
-        if (val instanceof Number){
-            return ((Number) val).doubleValue();
-        }
-        if (val instanceof String) {
-            try {
-                return Double.parseDouble((String) val);
-            } catch (Exception e) {
-                return defaultValue;
-            }
-        }
-        return defaultValue;
+        final double doubleValue = val.doubleValue();
+        // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
+        // return defaultValue;
+        // }
+        return doubleValue;
     }
 
     /**
@@ -1260,21 +1274,15 @@ public class JSONObject {
      * @return The value.
      */
     public float optFloat(String key, float defaultValue) {
-        Object val = this.opt(key);
-        if (JSONObject.NULL.equals(val)) {
+        Number val = this.optNumber(key);
+        if (val == null) {
             return defaultValue;
         }
-        if (val instanceof Number){
-            return ((Number) val).floatValue();
-        }
-        if (val instanceof String) {
-            try {
-                return Float.parseFloat((String) val);
-            } catch (Exception e) {
-                return defaultValue;
-            }
-        }
-        return defaultValue;
+        final float floatValue = val.floatValue();
+        // if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
+        // return defaultValue;
+        // }
+        return floatValue;
     }
 
     /**
@@ -1302,22 +1310,11 @@ public class JSONObject {
      * @return An object which is the value.
      */
     public int optInt(String key, int defaultValue) {
-        Object val = this.opt(key);
-        if (NULL.equals(val)) {
+        final Number val = this.optNumber(key, null);
+        if (val == null) {
             return defaultValue;
         }
-        if (val instanceof Number){
-            return ((Number) val).intValue();
-        }
-        
-        if (val instanceof String) {
-            try {
-                return new BigDecimal((String) val).intValue();
-            } catch (Exception e) {
-                return defaultValue;
-            }
-        }
-        return defaultValue;
+        return val.intValue();
     }
 
     /**
@@ -1371,22 +1368,12 @@ public class JSONObject {
      * @return An object which is the value.
      */
     public long optLong(String key, long defaultValue) {
-        Object val = this.opt(key);
-        if (NULL.equals(val)) {
+        final Number val = this.optNumber(key, null);
+        if (val == null) {
             return defaultValue;
         }
-        if (val instanceof Number){
-            return ((Number) val).longValue();
-        }
         
-        if (val instanceof String) {
-            try {
-                return new BigDecimal((String) val).longValue();
-            } catch (Exception e) {
-                return defaultValue;
-            }
-        }
-        return defaultValue;
+        return val.longValue();
     }
     
     /**
@@ -1424,14 +1411,11 @@ public class JSONObject {
             return (Number) val;
         }
         
-        if (val instanceof String) {
-            try {
-                return stringToNumber((String) val);
-            } catch (Exception e) {
-                return defaultValue;
-            }
+        try {
+            return stringToNumber(val.toString());
+        } catch (Exception e) {
+            return defaultValue;
         }
-        return defaultValue;
     }
     
     /**
@@ -1823,8 +1807,10 @@ public class JSONObject {
      * are both non-null, and only if there is not already a member with that
      * name.
      *
-     * @param key string
-     * @param value object
+     * @param key
+     *            key to insert into
+     * @param value
+     *            value to insert
      * @return this.
      * @throws JSONException
      *             if the key is a duplicate
@@ -1935,9 +1921,10 @@ public class JSONObject {
 
     /**
      * Produce a string in double quotes with backslash sequences in all the
-     * right places. A backslash will be inserted within = '0' && initial <= '9') || initial == '-') {
             try {
-                // if we want full Big Number support this block can be replaced with:
+                // if we want full Big Number support the contents of this
+                // `try` block can be replaced with:
                 // return stringToNumber(string);
                 if (isDecimalNotation(string)) {
                     Double d = Double.valueOf(string);
@@ -2414,13 +2406,9 @@ public class JSONObject {
         } else if (value instanceof Number) {
             // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
             final String numberAsString = numberToString((Number) value);
-            try {
-                // Use the BigDecimal constructor for its parser to validate the format.
-                @SuppressWarnings("unused")
-                BigDecimal testNum = new BigDecimal(numberAsString);
-                // Close enough to a JSON number that we will use it unquoted
+            if(NUMBER_PATTERN.matcher(numberAsString).matches()) {
                 writer.write(numberAsString);
-            } catch (NumberFormatException ex){
+            } else {
                 // The Number value is not a valid JSON number.
                 // Instead we will quote it as a string
                 quote(numberAsString, writer);
diff --git a/JSONPointer.java b/JSONPointer.java
index fc0b04b..df06f22 100644
--- a/JSONPointer.java
+++ b/JSONPointer.java
@@ -233,8 +233,8 @@ public class JSONPointer {
             int index = Integer.parseInt(indexToken);
             JSONArray currentArr = (JSONArray) current;
             if (index >= currentArr.length()) {
-                throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index,
-                        currentArr.length()));
+                throw new JSONPointerException(format("index %s is out of bounds - the array has %d elements", indexToken,
+                        Integer.valueOf(currentArr.length())));
             }
             try {
 				return currentArr.get(index);
diff --git a/JSONWriter.java b/JSONWriter.java
index e487781..19f2dc8 100644
--- a/JSONWriter.java
+++ b/JSONWriter.java
@@ -1,7 +1,6 @@
 package org.json;
 
 import java.io.IOException;
-import java.math.BigDecimal;
 import java.util.Collection;
 import java.util.Map;
 
@@ -326,31 +325,27 @@ public class JSONWriter {
             return "null";
         }
         if (value instanceof JSONString) {
-            Object object;
+            String object;
             try {
                 object = ((JSONString) value).toJSONString();
             } catch (Exception e) {
                 throw new JSONException(e);
             }
-            if (object instanceof String) {
-                return (String) object;
+            if (object != null) {
+                return object;
             }
             throw new JSONException("Bad value from toJSONString: " + object);
         }
         if (value instanceof Number) {
             // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
             final String numberAsString = JSONObject.numberToString((Number) value);
-            try {
-                // Use the BigDecimal constructor for it's parser to validate the format.
-                @SuppressWarnings("unused")
-                BigDecimal unused = new BigDecimal(numberAsString);
+            if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
                 // Close enough to a JSON number that we will return it unquoted
                 return numberAsString;
-            } catch (NumberFormatException ex){
-                // The Number value is not a valid JSON number.
-                // Instead we will quote it as a string
-                return JSONObject.quote(numberAsString);
             }
+            // The Number value is not a valid JSON number.
+            // Instead we will quote it as a string
+            return JSONObject.quote(numberAsString);
         }
         if (value instanceof Boolean || value instanceof JSONObject
                 || value instanceof JSONArray) {
diff --git a/XMLTokener.java b/XMLTokener.java
index 50e3acc..8490bec 100644
--- a/XMLTokener.java
+++ b/XMLTokener.java
@@ -135,7 +135,7 @@ public class XMLTokener extends JSONTokener {
      * @return  A Character or an entity String if the entity is not recognized.
      * @throws JSONException If missing ';' in XML entity.
      */
-    public Object nextEntity(char ampersand) throws JSONException {
+    public Object nextEntity(@SuppressWarnings("unused") char ampersand) throws JSONException {
         StringBuilder sb = new StringBuilder();
         for (;;) {
             char c = next();