0
# Streaming JSON Output
1
2
Advanced JSON writing and serialization using `JsonOutput` for memory-efficient generation of JSON documents. Provides fine-grained control over the serialization process, pretty printing options, and streaming output to any `Appendable` destination.
3
4
## Capabilities
5
6
### JsonOutput Class
7
8
Streaming JSON output processor that implements `Closeable` for resource management.
9
10
```java { .api }
11
/**
12
* The JsonOutput class defines the operations used to serialize Java objects into JSON strings.
13
* Provides streaming output capabilities and fine-grained control over JSON generation.
14
*/
15
public class JsonOutput implements Closeable {
16
17
// Configuration methods
18
19
/**
20
* Specify whether the serialized JSON object should be formatted with line breaks and indentation ("pretty printed").
21
*
22
* @param enablePrettyPrinting false for compact format; true for "pretty printing" (default: true)
23
* @return this JsonOutput object
24
*/
25
public JsonOutput setPrettyPrint(boolean enablePrettyPrinting);
26
27
/**
28
* Specify whether the serialized JSON object should include a "class" property whose value is the
29
* fully-qualified class name of the Java object being serialized.
30
*
31
* @param writeClassName Whether to include the "class" property (default: true)
32
* @return this JsonOutput object
33
*/
34
public JsonOutput writeClassName(boolean writeClassName);
35
36
// Object construction methods
37
38
/**
39
* Begin a new JSON object.
40
*
41
* @return this JsonOutput object
42
*/
43
public JsonOutput beginObject();
44
45
/**
46
* Set the name of a new JSON object property.
47
*
48
* @param name JSON object property name
49
* @return this JsonOutput object
50
* @throws JsonException if top item on serialization object stack isn't a JsonObject
51
* @throws java.util.NoSuchElementException if serialization object stack is empty
52
*/
53
public JsonOutput name(String name);
54
55
/**
56
* End the current JSON object.
57
*
58
* @return this JsonOutput object
59
* @throws JsonException if top item on serialization object stack isn't a JsonObject
60
* @throws java.util.NoSuchElementException if serialization object stack is empty
61
*/
62
public JsonOutput endObject();
63
64
// Array construction methods
65
66
/**
67
* Begin a new JSON array.
68
*
69
* @return this JsonOutput object
70
*/
71
public JsonOutput beginArray();
72
73
/**
74
* End the current JSON array.
75
*
76
* @return this JsonOutput object
77
* @throws JsonException if top item on serialization object stack isn't a JsonCollection
78
* @throws java.util.NoSuchElementException if serialization object stack is empty
79
*/
80
public JsonOutput endArray();
81
82
// Value writing methods
83
84
/**
85
* Serialize the specified Java object as a JSON value.
86
* Uses the default maximum depth limit.
87
*
88
* @param value Java object to serialize
89
* @return this JsonOutput object
90
* @throws JsonException if allowed depth has been reached
91
*/
92
public JsonOutput write(Object value);
93
94
/**
95
* Serialize the specified Java object as a JSON value.
96
*
97
* @param value Java object to serialize
98
* @param maxDepth maximum depth of nested object traversal
99
* @return this JsonOutput object
100
* @throws JsonException if allowed depth has been reached
101
*/
102
public JsonOutput write(Object value, int maxDepth);
103
104
// Resource management
105
106
/**
107
* Close the output stream.
108
*
109
* @throws JsonException if JSON stream isn't empty or an I/O exception is encountered
110
* @throws java.util.NoSuchElementException if serialization object stack is empty
111
*/
112
public void close();
113
}
114
```
115
116
### Constants
117
118
```java { .api }
119
/**
120
* Default maximum depth for object traversal during serialization
121
*/
122
public static final int MAX_DEPTH = 100;
123
```
124
125
## Usage Examples
126
127
### Basic Streaming Output
128
129
```java
130
import org.openqa.selenium.json.Json;
131
import org.openqa.selenium.json.JsonOutput;
132
import java.io.StringWriter;
133
134
Json json = new Json();
135
StringWriter writer = new StringWriter();
136
137
try (JsonOutput output = json.newOutput(writer)) {
138
output.beginObject()
139
.name("name").write("John")
140
.name("age").write(30)
141
.name("active").write(true)
142
.endObject();
143
}
144
145
String result = writer.toString();
146
// Result: {"name":"John","age":30,"active":true}
147
```
148
149
### Pretty Printing
150
151
```java
152
StringWriter writer = new StringWriter();
153
154
try (JsonOutput output = json.newOutput(writer)) {
155
output.setPrettyPrint(true) // Enable pretty printing
156
.beginObject()
157
.name("user")
158
.beginObject()
159
.name("name").write("John")
160
.name("age").write(30)
161
.endObject()
162
.name("timestamp").write(System.currentTimeMillis())
163
.endObject();
164
}
165
166
String result = writer.toString();
167
/* Result:
168
{
169
"user": {
170
"name": "John",
171
"age": 30
172
},
173
"timestamp": 1703508600000
174
}
175
*/
176
```
177
178
### Array Output
179
180
```java
181
StringWriter writer = new StringWriter();
182
183
try (JsonOutput output = json.newOutput(writer)) {
184
output.beginArray()
185
.write("apple")
186
.write("banana")
187
.write("cherry")
188
.endArray();
189
}
190
191
String result = writer.toString();
192
// Result: ["apple","banana","cherry"]
193
```
194
195
### Complex Nested Structures
196
197
```java
198
StringWriter writer = new StringWriter();
199
200
try (JsonOutput output = json.newOutput(writer)) {
201
output.setPrettyPrint(true)
202
.beginObject()
203
.name("users")
204
.beginArray()
205
206
// First user
207
.beginObject()
208
.name("id").write(1)
209
.name("name").write("John")
210
.name("roles")
211
.beginArray()
212
.write("admin")
213
.write("user")
214
.endArray()
215
.endObject()
216
217
// Second user
218
.beginObject()
219
.name("id").write(2)
220
.name("name").write("Jane")
221
.name("roles")
222
.beginArray()
223
.write("user")
224
.endArray()
225
.endObject()
226
227
.endArray()
228
.name("totalCount").write(2)
229
.endObject();
230
}
231
232
String result = writer.toString();
233
/* Result:
234
{
235
"users": [
236
{
237
"id": 1,
238
"name": "John",
239
"roles": ["admin", "user"]
240
},
241
{
242
"id": 2,
243
"name": "Jane",
244
"roles": ["user"]
245
}
246
],
247
"totalCount": 2
248
}
249
*/
250
```
251
252
### Object Serialization with Custom Options
253
254
```java
255
StringWriter writer = new StringWriter();
256
257
// Custom object for serialization
258
Person person = new Person("John Doe", 30);
259
260
try (JsonOutput output = json.newOutput(writer)) {
261
output.writeClassName(false) // Don't include class names
262
.setPrettyPrint(false) // Compact output
263
.write(person); // Serialize the object
264
}
265
266
String result = writer.toString();
267
// Result: {"name":"John Doe","age":30}
268
```
269
270
### Depth-Limited Serialization
271
272
```java
273
// Create a deeply nested object structure
274
NestedObject deepObject = createDeeplyNestedObject();
275
276
StringWriter writer = new StringWriter();
277
278
try (JsonOutput output = json.newOutput(writer)) {
279
// Limit depth to prevent infinite recursion or very deep structures
280
output.write(deepObject, 5); // Max depth of 5 levels
281
}
282
283
String result = writer.toString();
284
```
285
286
### Streaming to Different Appendables
287
288
```java
289
// Stream to StringBuilder
290
StringBuilder sb = new StringBuilder();
291
try (JsonOutput output = json.newOutput(sb)) {
292
output.beginObject()
293
.name("message").write("Hello World")
294
.endObject();
295
}
296
297
// Stream to System.out
298
try (JsonOutput output = json.newOutput(System.out)) {
299
output.beginObject()
300
.name("message").write("Printed to console")
301
.endObject();
302
}
303
304
// Stream to FileWriter
305
try (FileWriter fileWriter = new FileWriter("output.json");
306
JsonOutput output = json.newOutput(fileWriter)) {
307
output.beginObject()
308
.name("data").write(myData)
309
.endObject();
310
}
311
```
312
313
### Conditional Property Writing
314
315
```java
316
StringWriter writer = new StringWriter();
317
318
try (JsonOutput output = json.newOutput(writer)) {
319
output.beginObject()
320
.name("name").write("John");
321
322
// Conditionally add properties
323
if (includeAge) {
324
output.name("age").write(30);
325
}
326
327
if (includeEmail && email != null) {
328
output.name("email").write(email);
329
}
330
331
output.endObject();
332
}
333
```
334
335
### Error Handling
336
337
```java
338
StringWriter writer = new StringWriter();
339
340
try (JsonOutput output = json.newOutput(writer)) {
341
output.beginObject()
342
.name("data");
343
344
try {
345
// This might throw an exception due to circular references or depth limits
346
output.write(potentiallyProblematicObject, 10);
347
} catch (JsonException e) {
348
// Handle serialization error - write error info instead
349
output.beginObject()
350
.name("error").write("Serialization failed")
351
.name("message").write(e.getMessage())
352
.endObject();
353
}
354
355
output.endObject();
356
} catch (JsonException e) {
357
System.err.println("JSON output error: " + e.getMessage());
358
}
359
```
360
361
### Working with Collections and Maps
362
363
```java
364
List<String> items = Arrays.asList("apple", "banana", "cherry");
365
Map<String, Integer> counts = Map.of("apples", 5, "bananas", 3, "cherries", 8);
366
367
StringWriter writer = new StringWriter();
368
369
try (JsonOutput output = json.newOutput(writer)) {
370
output.beginObject()
371
.name("items").write(items) // Automatic array serialization
372
.name("counts").write(counts) // Automatic object serialization
373
.endObject();
374
}
375
376
String result = writer.toString();
377
// Result: {"items":["apple","banana","cherry"],"counts":{"apples":5,"bananas":3,"cherries":8}}
378
```