Skip to content

Commit 8a1b5a1

Browse files
committed
restructure JSONWriter as a state machine
1 parent 59e1a29 commit 8a1b5a1

2 files changed

Lines changed: 82 additions & 82 deletions

File tree

‎JSONArray.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ public JSONArray(Collection<?> collection) {
155155
}
156156
}
157157

158+
/**
159+
* Construct a JSONArray from an array
160+
* @param <T> The type of the array elements
161+
*/
162+
@SafeVarargs
163+
public <T> JSONArray(T... array) {
164+
this();
165+
for (T x : array) {
166+
this.put(JSONObject.wrap(x));
167+
}
168+
}
169+
158170
/**
159171
* Construct a JSONArray from an array
160172
*

‎JSONWriter.java‎

Lines changed: 70 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.IOException;
44
import java.io.Writer;
5+
import java.util.BitSet;
56

67
/*
78
Copyright (c) 2006 JSON.org
@@ -50,35 +51,33 @@ of this software and associated documentation files (the "Software"), to deal
5051
* <p>
5152
* The first method called must be <code>array</code> or <code>object</code>.
5253
* There are no methods for adding commas or colons. JSONWriter adds them for
53-
* you. Objects and arrays can be nested up to 200 levels deep.
54+
* you.
5455
* <p>
5556
* This can sometimes be easier than using a JSONObject to build a string.
5657
* @author JSON.org
5758
* @version 2015-12-09
5859
*/
5960
public class JSONWriter {
60-
private static final int maxdepth = 200;
61-
62-
/**
63-
* The comma flag determines if a comma should be output before the next
64-
* value.
65-
*/
66-
private boolean comma;
67-
6861
/**
6962
* The current mode. Values:
7063
* 'a' (array),
71-
* 'd' (done),
72-
* 'i' (initial),
73-
* 'k' (key),
74-
* 'o' (object).
64+
* 'A' (array after first element),
65+
* 'i' (initial/done),
66+
* 'k' (object: key),
67+
* 'o' (object: value),
68+
* 'K' (object: key after first element).
69+
*
70+
* The stack top is completely determined by the mode: it is empty in modes
71+
* 'i', 'd', true (object) in modes 'k', 'o', 'K', and false (array) in
72+
* modes 'a', 'A'.
7573
*/
7674
protected char mode;
7775

7876
/**
79-
* The object/array stack.
77+
* The object/array stack. Stored as a BitSet, where objects are true and
78+
* arrays are false.
8079
*/
81-
private final char stack[];
80+
private final BitSet stack;
8281

8382
/**
8483
* The stack top index. A value of 0 indicates that the stack is empty.
@@ -94,9 +93,8 @@ public class JSONWriter {
9493
* Make a fresh JSONWriter. It can be used to build one JSON text.
9594
*/
9695
public JSONWriter(Writer w) {
97-
comma = false;
9896
mode = 'i';
99-
stack = new char[maxdepth];
97+
stack = new BitSet();
10098
top = 0;
10199
writer = w;
102100
}
@@ -111,22 +109,35 @@ private JSONWriter append(String string) throws JSONException {
111109
if (string == null) {
112110
throw new JSONException("Null pointer");
113111
}
114-
if (mode == 'o' || mode == 'a') {
115-
try {
116-
if (comma && mode == 'a') {
117-
writer.write(',');
118-
}
119-
writer.write(string);
120-
} catch (IOException e) {
121-
throw new JSONException(e);
122-
}
123-
if (mode == 'o') {
124-
mode = 'k';
112+
if (mode == 'd') {
113+
throw new JSONException("Value out of sequence.");
114+
}
115+
try {
116+
if (mode == 'A' || mode == 'K') {
117+
writer.write(',');
118+
} else if (mode == 'o') {
119+
writer.write(':');
125120
}
126-
comma = true;
127-
return this;
121+
writer.write(string);
122+
} catch (IOException e) {
123+
throw new JSONException(e);
124+
}
125+
switch (mode) {
126+
case 'a':
127+
mode = 'A';
128+
break;
129+
case 'k':
130+
case 'K':
131+
mode = 'o';
132+
break;
133+
case 'o':
134+
mode = 'K';
135+
break;
136+
case 'i':
137+
mode = 'd';
138+
break;
128139
}
129-
throw new JSONException("Value out of sequence.");
140+
return this;
130141
}
131142

132143
/**
@@ -139,10 +150,9 @@ private JSONWriter append(String string) throws JSONException {
139150
* outermost array or object).
140151
*/
141152
public JSONWriter array() throws JSONException {
142-
if (mode == 'i' || mode == 'o' || mode == 'a') {
143-
push('a');
153+
if (mode == 'i' || mode == 'o' || mode == 'a' || mode == 'A') {
144154
append("[");
145-
comma = false;
155+
push(false);
146156
return this;
147157
}
148158
throw new JSONException("Misplaced array.");
@@ -155,19 +165,13 @@ public JSONWriter array() throws JSONException {
155165
* @return this
156166
* @throws JSONException If unbalanced.
157167
*/
158-
private JSONWriter end(char mode, char c) throws JSONException {
159-
if (this.mode != mode) {
160-
throw new JSONException(mode == 'a'
161-
? "Misplaced endArray."
162-
: "Misplaced endObject.");
163-
}
164-
pop(mode);
168+
private JSONWriter end(char c) throws JSONException {
169+
pop();
165170
try {
166171
writer.write(c);
167172
} catch (IOException e) {
168173
throw new JSONException(e);
169174
}
170-
comma = true;
171175
return this;
172176
}
173177

@@ -178,7 +182,10 @@ private JSONWriter end(char mode, char c) throws JSONException {
178182
* @throws JSONException If incorrectly nested.
179183
*/
180184
public JSONWriter endArray() throws JSONException {
181-
return end('a', ']');
185+
if (mode != 'a' && mode != 'A') {
186+
throw new JSONException("Misplaced endArray.");
187+
}
188+
return end(']');
182189
}
183190

184191
/**
@@ -188,7 +195,10 @@ public JSONWriter endArray() throws JSONException {
188195
* @throws JSONException If incorrectly nested.
189196
*/
190197
public JSONWriter endObject() throws JSONException {
191-
return end('k', '}');
198+
if (mode != 'k' && mode != 'K') {
199+
throw new JSONException("Misplaced endObject.");
200+
}
201+
return end('}');
192202
}
193203

194204
/**
@@ -200,16 +210,18 @@ public JSONWriter endObject() throws JSONException {
200210
public JSONWriter end() throws JSONException {
201211
char bracket;
202212
switch (mode) {
203-
case 'a':
213+
case 'a':
214+
case 'A':
204215
bracket = ']';
205216
break;
206-
case 'o':
217+
case 'k':
218+
case 'K':
207219
bracket = '}';
208220
break;
209221
default:
210222
throw new JSONException("Misplaced end.");
211223
}
212-
return end(mode, bracket);
224+
return end(bracket);
213225
}
214226

215227
/**
@@ -224,19 +236,8 @@ public JSONWriter key(String string) throws JSONException {
224236
if (string == null) {
225237
throw new JSONException("Null key.");
226238
}
227-
if (mode == 'k') {
228-
try {
229-
if (comma) {
230-
writer.write(',');
231-
}
232-
writer.write(JSONObject.quote(string));
233-
writer.write(':');
234-
comma = false;
235-
mode = 'o';
236-
return this;
237-
} catch (IOException e) {
238-
throw new JSONException(e);
239-
}
239+
if (mode == 'k' || mode == 'K') {
240+
return append(JSONObject.quote(string));
240241
}
241242
throw new JSONException("Misplaced key.");
242243
}
@@ -252,13 +253,9 @@ public JSONWriter key(String string) throws JSONException {
252253
* outermost array or object).
253254
*/
254255
public JSONWriter object() throws JSONException {
255-
if (mode == 'i') {
256-
mode = 'o';
257-
}
258-
if (mode == 'o' || mode == 'a') {
256+
if (mode == 'i' || mode == 'o' || mode == 'a' || mode == 'A') {
259257
append("{");
260-
push('k');
261-
comma = false;
258+
push(true);
262259
return this;
263260
}
264261
throw new JSONException("Misplaced object.");
@@ -268,33 +265,24 @@ public JSONWriter object() throws JSONException {
268265

269266
/**
270267
* Pop an array or object scope.
271-
* @param c The scope to close.
272268
* @throws JSONException If nesting is wrong.
273269
*/
274-
private void pop(char c) throws JSONException {
270+
private void pop() throws JSONException {
275271
if (top <= 0) {
276272
throw new JSONException("Nesting error.");
277273
}
278-
char m = stack[top - 1];
279-
if (m != c) {
280-
throw new JSONException("Nesting error.");
281-
}
282-
top -= 1;
283-
mode = top == 0 ? 'd' : stack[top - 1];
274+
top--;
275+
mode = top == 0 ? 'd' : stack.get(top - 1) ? 'K' : 'A';
284276
}
285277

286278
/**
287279
* Push an array or object scope.
288-
* @param jo The scope to open.
280+
* @param b The scope to open.
289281
* @throws JSONException If nesting is too deep.
290282
*/
291-
private void push(char jo) throws JSONException {
292-
if (top >= maxdepth) {
293-
throw new JSONException("Nesting too deep.");
294-
}
295-
stack[top] = jo;
296-
mode = jo;
297-
top += 1;
283+
private void push(boolean b) throws JSONException {
284+
stack.set(top++, b);
285+
mode = b ? 'k' : 'a';
298286
}
299287

300288

0 commit comments

Comments
 (0)