Skip to content

Commit 66b5f2f

Browse files
committed
added explicit containment hierarchy, for practical traversal
1 parent e9f9fe2 commit 66b5f2f

3 files changed

Lines changed: 80 additions & 23 deletions

File tree

JSON-java/src/org/json/JSONArray.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ of this software and associated documentation files (the "Software"), to deal
7979
* @author JSON.org
8080
* @version 2012-04-20
8181
*/
82-
public class JSONArray implements Serializable {
82+
public class JSONArray extends JSONType implements Serializable {
8383

8484
/**
8585
* Generated on January 20th, 2013.
@@ -91,6 +91,22 @@ public class JSONArray implements Serializable {
9191
*/
9292
private final ArrayList<Object> myArrayList;
9393

94+
private void setParent(Object object, JSONArray parent) {
95+
if( object != null && object instanceof JSONType ) {
96+
((JSONType) object).setParent(parent);
97+
}
98+
}
99+
100+
private void store(Object object) {
101+
setParent(object, this);
102+
this.myArrayList.add(object);
103+
}
104+
105+
private void store(int index, Object object) {
106+
setParent(object, this);
107+
this.myArrayList.set(index, object);
108+
}
109+
94110

95111
/**
96112
* Construct an empty JSONArray.
@@ -114,10 +130,10 @@ public JSONArray(JSONTokener x) throws JSONException {
114130
for (;;) {
115131
if (x.nextClean() == ',') {
116132
x.back();
117-
this.myArrayList.add(JSONObject.NULL);
133+
this.store(JSONObject.NULL);
118134
} else {
119135
x.back();
120-
this.myArrayList.add(x.nextValue());
136+
this.store(x.nextValue());
121137
}
122138
switch (x.nextClean()) {
123139
case ';':
@@ -157,7 +173,7 @@ public JSONArray(Collection<?> collection) {
157173
this.myArrayList = new ArrayList<Object>();
158174
if (collection != null) {
159175
for( Object object : collection ) {
160-
this.myArrayList.add(JSONObject.wrap(object));
176+
this.store(JSONObject.wrap(object));
161177
}
162178
}
163179
}
@@ -644,7 +660,7 @@ public JSONArray put(Map<String, Object> value) {
644660
* @return this.
645661
*/
646662
public JSONArray put(Object value) {
647-
this.myArrayList.add(value);
663+
this.store(value);
648664
return this;
649665
}
650666

@@ -758,7 +774,7 @@ public JSONArray put(int index, Object value) throws JSONException {
758774
throw new JSONException("JSONArray[" + index + "] not found.");
759775
}
760776
if (index < this.length()) {
761-
this.myArrayList.set(index, value);
777+
this.store(index, value);
762778
} else {
763779
while (index != this.length()) {
764780
this.put(JSONObject.NULL);
@@ -776,9 +792,10 @@ public JSONArray put(int index, Object value) throws JSONException {
776792
* or null if there was no value.
777793
*/
778794
public Object remove(int index) {
779-
Object o = this.opt(index);
795+
final Object object = this.opt(index);
796+
setParent(object, null);
780797
this.myArrayList.remove(index);
781-
return o;
798+
return object;
782799
}
783800

784801

@@ -795,11 +812,11 @@ public JSONObject toJSONObject(JSONArray names) throws JSONException {
795812
if (names == null || names.length() == 0 || this.length() == 0) {
796813
return null;
797814
}
798-
JSONObject jo = new JSONObject();
815+
JSONObject jsonObject = new JSONObject();
799816
for (int i = 0; i < names.length(); i += 1) {
800-
jo.put(names.getString(i), this.opt(i));
817+
jsonObject.put(names.getString(i), this.opt(i));
801818
}
802-
return jo;
819+
return jsonObject;
803820
}
804821

805822

JSON-java/src/org/json/JSONObject.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ of this software and associated documentation files (the "Software"), to deal
9393
* @author JSON.org
9494
* @version 2012-07-02
9595
*/
96-
public class JSONObject implements Serializable {
96+
public class JSONObject extends JSONType implements Serializable {
9797

9898
/**
9999
* Generated on January 20th, 2013.
@@ -141,6 +141,12 @@ public String toString() {
141141
*/
142142
private final Map<String, Object> map;
143143

144+
private void store(String key, Object object) {
145+
this.map.put(key, object);
146+
if( object instanceof JSONType ) {
147+
((JSONType) object).setParent(this);
148+
}
149+
}
144150

145151
/**
146152
* It is sometimes more convenient and less ambiguous to have a
@@ -249,7 +255,7 @@ public JSONObject(Map<String, Object> map) {
249255
for( Map.Entry<String, Object> e : map.entrySet() ) {
250256
Object value = e.getValue();
251257
if (value != null) {
252-
this.map.put(e.getKey(), wrap(value));
258+
this.store(e.getKey(), wrap(value));
253259
}
254260
}
255261
}
@@ -997,7 +1003,7 @@ private void populateMap(Object bean) {
9971003

9981004
Object result = method.invoke(bean, (Object[])null);
9991005
if (result != null) {
1000-
this.map.put(key, wrap(result));
1006+
this.store(key, wrap(result));
10011007
}
10021008
}
10031009
}
@@ -1108,7 +1114,7 @@ public JSONObject put(String key, Object value) throws JSONException {
11081114
}
11091115
if (value != null) {
11101116
testValidity(value);
1111-
this.map.put(key, value);
1117+
this.store(key, value);
11121118
} else {
11131119
this.remove(key);
11141120
}
@@ -1238,6 +1244,10 @@ public static Writer quote(String string, Writer w) throws IOException {
12381244
* or null if there was no value.
12391245
*/
12401246
public Object remove(String key) {
1247+
final Object object = this.map.get(key);
1248+
if( object != null && object instanceof JSONType ) {
1249+
((JSONType) object).setParent(null);
1250+
}
12411251
return this.map.remove(key);
12421252
}
12431253

@@ -1296,18 +1306,18 @@ public static Object stringToValue(String string) {
12961306

12971307
/**
12981308
* Throw an exception if the object is a NaN or infinite number.
1299-
* @param o The object to test.
1300-
* @throws JSONException If o is a non-finite number.
1309+
* @param object The object to test.
1310+
* @throws JSONException If object is a non-finite number.
13011311
*/
1302-
public static void testValidity(Object o) throws JSONException {
1303-
if (o != null) {
1304-
if (o instanceof Double) {
1305-
if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
1312+
public static void testValidity(Object object) throws JSONException {
1313+
if (object != null) {
1314+
if (object instanceof Double) {
1315+
if (((Double) object).isInfinite() || ((Double) object).isNaN()) {
13061316
throw new JSONException(
13071317
"JSON does not allow non-finite numbers.");
13081318
}
1309-
} else if (o instanceof Float) {
1310-
if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
1319+
} else if (object instanceof Float) {
1320+
if (((Float) object).isInfinite() || ((Float) object).isNaN()) {
13111321
throw new JSONException(
13121322
"JSON does not allow non-finite numbers.");
13131323
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.json;
2+
3+
/**
4+
* Common super type for {@link JSONArray} and {@link JSONObject},
5+
* primarily to make traversing up containment hierarchies possible.
6+
*
7+
* @author Meinte Boersma
8+
*/
9+
abstract class JSONType {
10+
11+
protected JSONType parent = null;
12+
13+
/**
14+
* @return The parent in the JSON containment tree or {@code null} if this is the root.
15+
*/
16+
public JSONType getParent() {
17+
return parent;
18+
}
19+
20+
/**
21+
* Sets the parent of this JSON object.
22+
* @param parent - the parent object, which assumes responsibility over the containment link.
23+
* @return This JSON object, for chaining.
24+
*/
25+
public <T extends JSONType> T setParent(T parent) {
26+
this.parent = parent;
27+
return parent; // for chaining (with correct generic type)
28+
}
29+
30+
}

0 commit comments

Comments
 (0)