Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into AndroidSupport
Browse files Browse the repository at this point in the history
  • Loading branch information
johnjaylward committed Oct 27, 2017
2 parents 3997a90 + cdf3cf7 commit 057e0c7
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 82 deletions.
48 changes: 39 additions & 9 deletions JSONArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -1230,7 +1230,7 @@ public Object optQuery(String jsonPointer) {
* Queries and returns a value from this object using {@code jsonPointer}, or
* returns null if the query fails due to a missing key.
*
* @param The JSON pointer
* @param jsonPointer The JSON pointer
* @return the queried value or {@code null}
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
Expand Down Expand Up @@ -1323,8 +1323,9 @@ public JSONObject toJSONObject(JSONArray names) throws JSONException {
* whitespace is added. If it is not possible to produce a syntactically
* correct JSON text then null will be returned instead. This could occur if
* the array contains an invalid number.
* <p>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @return a printable, displayable, transmittable representation of the
* array.
Expand All @@ -1339,9 +1340,24 @@ public String toString() {
}

/**
* Make a pretty-printed JSON text of this JSONArray. Warning: This method
* assumes that the data structure is acyclical.
*
* Make a pretty-printed JSON text of this JSONArray.
*
* <p>If <code>indentFactor > 0</code> and the {@link JSONArray} has only
* one element, then the array will be output on a single line:
* <pre>{@code [1]}</pre>
*
* <p>If an array has 2 or more elements, then it will be output across
* multiple lines: <pre>{@code
* [
* 1,
* "value 2",
* 3
* ]
* }</pre>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param indentFactor
* The number of spaces to add to each level of indentation.
* @return a printable, displayable, transmittable representation of the
Expand All @@ -1360,8 +1376,9 @@ public String toString(int indentFactor) throws JSONException {
/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
*</b>
*
* @return The writer.
* @throws JSONException
Expand All @@ -1371,10 +1388,23 @@ public Writer write(Writer writer) throws JSONException {
}

/**
* Write the contents of the JSONArray as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* Write the contents of the JSONArray as JSON text to a writer.
*
* <p>If <code>indentFactor > 0</code> and the {@link JSONArray} has only
* one element, then the array will be output on a single line:
* <pre>{@code [1]}</pre>
*
* <p>If an array has 2 or more elements, then it will be output across
* multiple lines: <pre>{@code
* [
* 1,
* "value 2",
* 3
* ]
* }</pre>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param writer
* Writes the serialized JSON
Expand Down
2 changes: 1 addition & 1 deletion JSONML.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ private static Object parse(
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
}
newjo.accumulate(attribute, keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token));
newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token));
token = null;
} else {
newjo.accumulate(attribute, "");
Expand Down
142 changes: 105 additions & 37 deletions JSONObject.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.json;

import java.io.Closeable;

/*
Copyright (c) 2002 JSON.org
Expand Down Expand Up @@ -28,6 +30,7 @@ of this software and associated documentation files (the "Software"), to deal
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
Expand Down Expand Up @@ -228,7 +231,21 @@ public JSONObject(JSONTokener x) throws JSONException {
if (c != ':') {
throw x.syntaxError("Expected a ':' after a key");
}
this.putOnce(key, x.nextValue());

// Use syntaxError(..) to include error location

if (key != null) {
// Check if key exists
if (this.opt(key) != null) {
// key already exists
throw x.syntaxError("Duplicate key \"" + key + "\"");
}
// Only add value if non-null
Object value = x.nextValue();
if (value!=null) {
this.put(key, value);
}
}

// Pairs are separated by ','.

Expand Down Expand Up @@ -276,16 +293,19 @@ public JSONObject(Map<?, ?> m) {
* <code>"is"</code> 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.
*
* <p>
* The key is formed by removing the <code>"get"</code> or <code>"is"</code>
* prefix. If the second remaining character is not upper case, then the
* first character is converted to lower case.
*
* <p>
* For example, if an object has a method named <code>"getName"</code>, and
* if the result of calling <code>object.getName()</code> is
* <code>"Larry Fine"</code>, then the JSONObject will contain
* <code>"name": "Larry Fine"</code>.
*
* <p>
* Methods that return <code>void</code> as well as <code>static</code>
* methods are ignored.
*
* @param bean
* An object that has getter methods that should be used to make
* a JSONObject.
Expand Down Expand Up @@ -1388,6 +1408,15 @@ public String optString(String key, String defaultValue) {
return NULL.equals(object) ? defaultValue : object.toString();
}

/**
* Populates the internal map of the JSONObject with the bean properties.
* The bean can not be recursive.
*
* @see JSONObject#JSONObject(Object)
*
* @param bean
* the bean
*/
private void populateMap(Object bean) {
Class<?> klass = bean.getClass();

Expand All @@ -1397,39 +1426,52 @@ private void populateMap(Object bean) {

Method[] methods = includeSuperClass ? klass.getMethods() : klass
.getDeclaredMethods();
for (int i = 0; i < methods.length; i += 1) {
try {
Method method = methods[i];
if (Modifier.isPublic(method.getModifiers())) {
String name = method.getName();
String key = "";
if (name.startsWith("get")) {
if ("getClass".equals(name)
|| "getDeclaringClass".equals(name)) {
key = "";
} else {
key = name.substring(3);
}
} else if (name.startsWith("is")) {
key = name.substring(2);
for (final Method method : methods) {
final int modifiers = method.getModifiers();
if (Modifier.isPublic(modifiers)
&& !Modifier.isStatic(modifiers)
&& method.getParameterTypes().length == 0
&& !method.isBridge()
&& method.getReturnType() != Void.TYPE ) {
final String name = method.getName();
String key;
if (name.startsWith("get")) {
if ("getClass".equals(name) || "getDeclaringClass".equals(name)) {
continue;
}
key = name.substring(3);
} else if (name.startsWith("is")) {
key = name.substring(2);
} else {
continue;
}
if (key.length() > 0
&& Character.isUpperCase(key.charAt(0))) {
if (key.length() == 1) {
key = key.toLowerCase(Locale.ROOT);
} else if (!Character.isUpperCase(key.charAt(1))) {
key = key.substring(0, 1).toLowerCase(Locale.ROOT)
+ key.substring(1);
}
if (key.length() > 0
&& Character.isUpperCase(key.charAt(0))
&& method.getParameterTypes().length == 0) {
if (key.length() == 1) {
key = key.toLowerCase(Locale.ROOT);
} else if (!Character.isUpperCase(key.charAt(1))) {
key = key.substring(0, 1).toLowerCase(Locale.ROOT)
+ key.substring(1);
}

Object result = method.invoke(bean, (Object[]) null);
try {
final Object result = method.invoke(bean);
if (result != null) {
this.map.put(key, wrap(result));
// we don't use the result anywhere outside of wrap
// if it's a resource we should be sure to close it after calling toString
if(result instanceof Closeable) {
try {
((Closeable)result).close();
} catch (IOException ignore) {
}
}
}
} catch (IllegalAccessException ignore) {
} catch (IllegalArgumentException ignore) {
} catch (InvocationTargetException ignore) {
}
}
} catch (Exception ignore) {
}
}
}
Expand Down Expand Up @@ -1676,7 +1718,7 @@ public Object optQuery(String jsonPointer) {
* Queries and returns a value from this object using {@code jsonPointer}, or
* returns null if the query fails due to a missing key.
*
* @param The JSON pointer
* @param jsonPointer The JSON pointer
* @return the queried value or {@code null}
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
*/
Expand Down Expand Up @@ -2004,9 +2046,10 @@ public JSONArray toJSONArray(JSONArray names) throws JSONException {
* Make a JSON text of this JSONObject. For compactness, no whitespace is
* added. If this would not result in a syntactically correct JSON text,
* then null will be returned instead.
* <p>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
*
* </b>
*
* @return a printable, displayable, portable, transmittable representation
* of the object, beginning with <code>{</code>&nbsp;<small>(left
* brace)</small> and ending with <code>}</code>&nbsp;<small>(right
Expand All @@ -2023,8 +2066,20 @@ public String toString() {

/**
* Make a pretty-printed JSON text of this JSONObject.
* <p>
*
* <p>If <code>indentFactor > 0</code> and the {@link JSONObject}
* has only one key, then the object will be output on a single line:
* <pre>{@code {"key": 1}}</pre>
*
* <p>If an object has 2 or more keys, then it will be output across
* multiple lines: <code><pre>{
* "key1": 1,
* "key2": "value 2",
* "key3": 3
* }</pre></code>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param indentFactor
* The number of spaces to add to each level of indentation.
Expand Down Expand Up @@ -2130,9 +2185,10 @@ public static Object wrap(Object object) {
/**
* Write the contents of the JSONObject as JSON text to a writer. For
* compactness, no whitespace is added.
* <p>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
*
* </b>
*
* @return The writer.
* @throws JSONException
*/
Expand Down Expand Up @@ -2196,8 +2252,20 @@ static final void indent(Writer writer, int indent) throws IOException {

/**
* Write the contents of the JSONObject as JSON text to a writer.
* <p>
*
* <p>If <code>indentFactor > 0</code> and the {@link JSONObject}
* has only one key, then the object will be output on a single line:
* <pre>{@code {"key": 1}}</pre>
*
* <p>If an object has 2 or more keys, then it will be output across
* multiple lines: <code><pre>{
* "key1": 1,
* "key2": "value 2",
* "key3": 3
* }</pre></code>
* <p><b>
* Warning: This method assumes that the data structure is acyclical.
* </b>
*
* @param writer
* Writes the serialized JSON
Expand Down
2 changes: 2 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ invalid number formats (1.2e6.3) will cause errors as such documents can not be
reliably.

Release history:
20171018 Checkpoint for recent commits.

20170516 Roll up recent commits.

20160810 Revert code that was breaking opt*() methods.
Expand Down
Loading

0 comments on commit 057e0c7

Please sign in to comment.