1 /*******************************************************************************
\r
2 * ============LICENSE_START==================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
25 import java.io.IOException;
\r
26 import java.io.Writer;
\r
30 public class JSONWriter {
\r
31 private static final int maxdepth = 200;
\r
34 * The comma flag determines if a comma should be output before the next
\r
37 private boolean comma;
\r
40 * The current mode. Values:
\r
47 protected char mode;
\r
50 * The object/array stack.
\r
52 private final JSONObject stack[];
\r
55 * The stack top index. A value of 0 indicates that the stack is empty.
\r
60 * The writer that will receive the output.
\r
62 protected Writer writer;
\r
65 * Make a fresh JSONWriter. It can be used to build one JSON text.
\r
67 public JSONWriter(Writer w) {
\r
70 this.stack = new JSONObject[maxdepth];
\r
77 * @param string A string value.
\r
79 * @throws JSONException If the value is out of sequence.
\r
81 private JSONWriter append(String string) throws JSONException {
\r
82 if (string == null) {
\r
83 throw new JSONException("Null pointer");
\r
85 if (this.mode == 'o' || this.mode == 'a') {
\r
87 if (this.comma && this.mode == 'a') {
\r
88 this.writer.write(',');
\r
90 this.writer.write(string);
\r
91 } catch (IOException e) {
\r
92 throw new JSONException(e);
\r
94 if (this.mode == 'o') {
\r
100 throw new JSONException("Value out of sequence.");
\r
104 * Begin appending a new array. All values until the balancing
\r
105 * <code>endArray</code> will be appended to this array. The
\r
106 * <code>endArray</code> method must be called to mark the array's end.
\r
108 * @throws JSONException If the nesting is too deep, or if the object is
\r
109 * started in the wrong place (for example as a key or after the end of the
\r
110 * outermost array or object).
\r
112 public JSONWriter array() throws JSONException {
\r
113 if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
\r
116 this.comma = false;
\r
119 throw new JSONException("Misplaced array.");
\r
125 * @param c Closing character
\r
127 * @throws JSONException If unbalanced.
\r
129 private JSONWriter end(char mode, char c) throws JSONException {
\r
130 if (this.mode != mode) {
\r
131 throw new JSONException(mode == 'a'
\r
132 ? "Misplaced endArray."
\r
133 : "Misplaced endObject.");
\r
137 this.writer.write(c);
\r
138 } catch (IOException e) {
\r
139 throw new JSONException(e);
\r
146 * End an array. This method most be called to balance calls to
\r
147 * <code>array</code>.
\r
149 * @throws JSONException If incorrectly nested.
\r
151 public JSONWriter endArray() throws JSONException {
\r
152 return this.end('a', ']');
\r
156 * End an object. This method most be called to balance calls to
\r
157 * <code>object</code>.
\r
159 * @throws JSONException If incorrectly nested.
\r
161 public JSONWriter endObject() throws JSONException {
\r
162 return this.end('k', '}');
\r
166 * Append a key. The key will be associated with the next value. In an
\r
167 * object, every value must be preceded by a key.
\r
168 * @param string A key string.
\r
170 * @throws JSONException If the key is out of place. For example, keys
\r
171 * do not belong in arrays or if the key is null.
\r
173 public JSONWriter key(String string) throws JSONException {
\r
174 if (string == null) {
\r
175 throw new JSONException("Null key.");
\r
177 if (this.mode == 'k') {
\r
179 this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
\r
181 this.writer.write(',');
\r
183 this.writer.write(JSONObject.quote(string));
\r
184 this.writer.write(':');
\r
185 this.comma = false;
\r
188 } catch (IOException e) {
\r
189 throw new JSONException(e);
\r
192 throw new JSONException("Misplaced key.");
\r
197 * Begin appending a new object. All keys and values until the balancing
\r
198 * <code>endObject</code> will be appended to this object. The
\r
199 * <code>endObject</code> method must be called to mark the object's end.
\r
201 * @throws JSONException If the nesting is too deep, or if the object is
\r
202 * started in the wrong place (for example as a key or after the end of the
\r
203 * outermost array or object).
\r
205 public JSONWriter object() throws JSONException {
\r
206 if (this.mode == 'i') {
\r
209 if (this.mode == 'o' || this.mode == 'a') {
\r
211 this.push(new JSONObject());
\r
212 this.comma = false;
\r
215 throw new JSONException("Misplaced object.");
\r
221 * Pop an array or object scope.
\r
222 * @param c The scope to close.
\r
223 * @throws JSONException If nesting is wrong.
\r
225 private void pop(char c) throws JSONException {
\r
226 if (this.top <= 0) {
\r
227 throw new JSONException("Nesting error.");
\r
229 char m = this.stack[this.top - 1] == null ? 'a' : 'k';
\r
231 throw new JSONException("Nesting error.");
\r
234 this.mode = this.top == 0
\r
236 : this.stack[this.top - 1] == null
\r
242 * Push an array or object scope.
\r
243 * @param jo The scope to open.
\r
244 * @throws JSONException If nesting is too deep.
\r
246 private void push(JSONObject jo) throws JSONException {
\r
247 if (this.top >= maxdepth) {
\r
248 throw new JSONException("Nesting too deep.");
\r
250 this.stack[this.top] = jo;
\r
251 this.mode = jo == null ? 'a' : 'k';
\r
257 * Append either the value <code>true</code> or the value
\r
258 * <code>false</code>.
\r
259 * @param b A boolean.
\r
261 * @throws JSONException
\r
263 public JSONWriter value(boolean b) throws JSONException {
\r
264 return this.append(b ? "true" : "false");
\r
268 * Append a double value.
\r
269 * @param d A double.
\r
271 * @throws JSONException If the number is not finite.
\r
273 public JSONWriter value(double d) throws JSONException {
\r
274 return this.value(new Double(d));
\r
278 * Append a long value.
\r
281 * @throws JSONException
\r
283 public JSONWriter value(long l) throws JSONException {
\r
284 return this.append(Long.toString(l));
\r
289 * Append an object value.
\r
290 * @param object The object to append. It can be null, or a Boolean, Number,
\r
291 * String, JSONObject, or JSONArray, or an object that implements JSONString.
\r
293 * @throws JSONException If the value is out of sequence.
\r
295 public JSONWriter value(Object object) throws JSONException {
\r
296 return this.append(JSONObject.valueToString(object));
\r