0
# Output Formatting and Configuration
1
2
JSON-Smart provides extensive configuration options through JSONStyle for controlling JSON output formatting, compression levels, and parser behavior. This document covers all configuration aspects for both serialization and parsing.
3
4
## JSONStyle - Output Formatting
5
6
JSONStyle controls how JSON is formatted during serialization, offering various compression levels and formatting options.
7
8
### Predefined Styles
9
10
```java { .api }
11
public static final JSONStyle NO_COMPRESS;
12
public static final JSONStyle MAX_COMPRESS;
13
public static final JSONStyle LT_COMPRESS;
14
```
15
16
Three predefined formatting styles for common use cases.
17
18
```java
19
JSONObject obj = new JSONObject()
20
.appendField("name", "John Doe")
21
.appendField("age", 30)
22
.appendField("active", true);
23
24
// No compression - readable formatting
25
String readable = obj.toJSONString(JSONStyle.NO_COMPRESS);
26
// {"name" : "John Doe", "age" : 30, "active" : true}
27
28
// Maximum compression - minimal size
29
String compressed = obj.toJSONString(JSONStyle.MAX_COMPRESS);
30
// {name:"John Doe",age:30,active:true}
31
32
// Light compression - balanced
33
String balanced = obj.toJSONString(JSONStyle.LT_COMPRESS);
34
// {"name":"John Doe","age":30,"active":true}
35
```
36
37
### Flag Constants
38
39
```java { .api }
40
public static final int FLAG_PROTECT_KEYS = 1;
41
public static final int FLAG_PROTECT_4WEB = 2;
42
public static final int FLAG_PROTECT_VALUES = 4;
43
public static final int FLAG_AGRESSIVE = 8;
44
public static final int FLAG_IGNORE_NULL = 16;
45
```
46
47
Individual flags that control specific formatting behaviors:
48
49
- **FLAG_PROTECT_KEYS**: Always quote object keys
50
- **FLAG_PROTECT_4WEB**: Use web-safe escaping
51
- **FLAG_PROTECT_VALUES**: Always quote string values
52
- **FLAG_AGRESSIVE**: Maximum compression (remove all unnecessary characters)
53
- **FLAG_IGNORE_NULL**: Skip null values in output
54
55
### Constructors
56
57
```java { .api }
58
public JSONStyle();
59
public JSONStyle(int FLAG);
60
```
61
62
Create custom formatting styles.
63
64
```java
65
// Default style
66
JSONStyle defaultStyle = new JSONStyle();
67
68
// Custom style with specific flags
69
JSONStyle customStyle = new JSONStyle(
70
JSONStyle.FLAG_PROTECT_KEYS | JSONStyle.FLAG_IGNORE_NULL
71
);
72
73
// Multiple flags combined
74
int webSafeFlags = JSONStyle.FLAG_PROTECT_KEYS |
75
JSONStyle.FLAG_PROTECT_4WEB |
76
JSONStyle.FLAG_IGNORE_NULL;
77
JSONStyle webSafe = new JSONStyle(webSafeFlags);
78
```
79
80
### Configuration Methods
81
82
```java { .api }
83
public boolean protectKeys();
84
public boolean protectValues();
85
public boolean protect4Web();
86
public boolean ignoreNull();
87
public boolean indent();
88
public boolean mustProtectKey(String s);
89
public boolean mustProtectValue(String s);
90
```
91
92
Query current configuration and test protection requirements.
93
94
```java
95
JSONStyle style = new JSONStyle(JSONStyle.FLAG_PROTECT_KEYS | JSONStyle.FLAG_IGNORE_NULL);
96
97
// Check configuration
98
boolean quotesKeys = style.protectKeys(); // true
99
boolean skipsNull = style.ignoreNull(); // true
100
boolean indented = style.indent(); // false
101
102
// Test specific values
103
boolean needsQuotes = style.mustProtectKey("validKey"); // true (always protect when flag set)
104
boolean valueNeedsQuotes = style.mustProtectValue("simple"); // depends on flag and content
105
```
106
107
## Output Formatting Examples
108
109
### Key Protection Examples
110
111
```java
112
JSONObject obj = new JSONObject()
113
.appendField("simpleKey", "value")
114
.appendField("key with spaces", "value")
115
.appendField("123numeric", "value")
116
.appendField("key-with-dashes", "value");
117
118
// Default style - quotes only when necessary
119
String normal = obj.toJSONString();
120
// {simpleKey:"value","key with spaces":"value","123numeric":"value","key-with-dashes":"value"}
121
122
// Always protect keys
123
JSONStyle protectKeys = new JSONStyle(JSONStyle.FLAG_PROTECT_KEYS);
124
String quoted = obj.toJSONString(protectKeys);
125
// {"simpleKey":"value","key with spaces":"value","123numeric":"value","key-with-dashes":"value"}
126
```
127
128
### Value Protection Examples
129
130
```java
131
JSONObject obj = new JSONObject()
132
.appendField("string", "simple")
133
.appendField("number", 42)
134
.appendField("boolean", true)
135
.appendField("special", "string with \"quotes\" and \n newlines");
136
137
// Default style
138
String normal = obj.toJSONString();
139
// {string:simple,number:42,boolean:true,special:"string with \"quotes\" and \n newlines"}
140
141
// Always protect string values
142
JSONStyle protectValues = new JSONStyle(JSONStyle.FLAG_PROTECT_VALUES);
143
String quoted = obj.toJSONString(protectValues);
144
// {string:"simple",number:42,boolean:true,special:"string with \"quotes\" and \n newlines"}
145
```
146
147
### Null Handling Examples
148
149
```java
150
JSONObject obj = new JSONObject()
151
.appendField("name", "John")
152
.appendField("middle", null)
153
.appendField("age", 30)
154
.appendField("email", null);
155
156
// Default style - includes nulls
157
String withNulls = obj.toJSONString();
158
// {name:"John",middle:null,age:30,email:null}
159
160
// Ignore null values
161
JSONStyle ignoreNull = new JSONStyle(JSONStyle.FLAG_IGNORE_NULL);
162
String noNulls = obj.toJSONString(ignoreNull);
163
// {name:"John",age:30}
164
```
165
166
### Web-Safe Formatting
167
168
```java
169
JSONObject obj = new JSONObject()
170
.appendField("html", "<script>alert('xss')</script>")
171
.appendField("path", "/api/users")
172
.appendField("callback", "jsonp_callback_123");
173
174
// Default style
175
String normal = obj.toJSONString();
176
// {html:"<script>alert('xss')</script>",path:"/api/users",callback:"jsonp_callback_123"}
177
178
// Web-safe escaping
179
JSONStyle webSafe = new JSONStyle(JSONStyle.FLAG_PROTECT_4WEB);
180
String safe = obj.toJSONString(webSafe);
181
// {html:"\\u003cscript\\u003ealert('xss')\\u003c\\/script\\u003e",path:"\\/api\\/users",callback:"jsonp_callback_123"}
182
```
183
184
## Output Writing Methods
185
186
JSONStyle provides methods for writing JSON output with specific formatting.
187
188
### String Writing
189
190
```java { .api }
191
public void writeString(Appendable out, String value) throws IOException;
192
public void escape(String s, Appendable out);
193
```
194
195
Write strings with appropriate escaping and quoting.
196
197
```java
198
JSONStyle style = new JSONStyle(JSONStyle.FLAG_PROTECT_VALUES);
199
StringBuilder sb = new StringBuilder();
200
201
// Write quoted string
202
style.writeString(sb, "Hello World");
203
System.out.println(sb.toString()); // "Hello World"
204
205
// Write with escaping
206
sb.setLength(0);
207
style.escape("Text with \"quotes\"", sb);
208
System.out.println(sb.toString()); // Text with \"quotes\"
209
```
210
211
### Structure Writing Methods
212
213
```java { .api }
214
public void objectStart(Appendable out) throws IOException;
215
public void objectStop(Appendable out) throws IOException;
216
public void objectFirstStart(Appendable out) throws IOException;
217
public void objectNext(Appendable out) throws IOException;
218
public void objectElmStop(Appendable out) throws IOException;
219
public void objectEndOfKey(Appendable out) throws IOException;
220
221
public void arrayStart(Appendable out) throws IOException;
222
public void arrayStop(Appendable out) throws IOException;
223
public void arrayfirstObject(Appendable out) throws IOException;
224
public void arrayNextElm(Appendable out) throws IOException;
225
public void arrayObjectEnd(Appendable out) throws IOException;
226
```
227
228
Low-level methods for manual JSON construction with consistent formatting.
229
230
```java
231
JSONStyle style = JSONStyle.NO_COMPRESS;
232
StringBuilder json = new StringBuilder();
233
234
// Manual object construction
235
style.objectStart(json); // {
236
style.objectFirstStart(json); //
237
json.append("\"name\"");
238
style.objectEndOfKey(json); // :
239
style.writeString(json, "John"); // "John"
240
style.objectNext(json); // ,
241
json.append("\"age\"");
242
style.objectEndOfKey(json); // :
243
json.append("30");
244
style.objectElmStop(json); //
245
style.objectStop(json); // }
246
247
System.out.println(json.toString()); // {"name" : "John", "age" : 30}
248
```
249
250
## Custom Style Creation
251
252
### Custom Compression Style
253
254
```java
255
// Create highly compressed style for APIs
256
public class APICompressionStyle extends JSONStyle {
257
258
public APICompressionStyle() {
259
super(FLAG_AGRESSIVE | FLAG_IGNORE_NULL | FLAG_PROTECT_4WEB);
260
}
261
262
@Override
263
public boolean mustProtectKey(String key) {
264
// Never protect keys that are simple identifiers
265
if (key.matches("^[a-zA-Z_][a-zA-Z0-9_]*$")) {
266
return false;
267
}
268
return super.mustProtectKey(key);
269
}
270
271
@Override
272
public boolean mustProtectValue(String value) {
273
// Don't protect simple numeric strings
274
if (value.matches("^\\d+$")) {
275
return false;
276
}
277
return super.mustProtectValue(value);
278
}
279
}
280
281
// Usage
282
JSONStyle apiStyle = new APICompressionStyle();
283
JSONObject data = new JSONObject()
284
.appendField("userId", "12345")
285
.appendField("status", "active")
286
.appendField("count", null);
287
288
String compressed = data.toJSONString(apiStyle);
289
// {userId:12345,status:active} (null ignored, minimal quotes)
290
```
291
292
### Debug-Friendly Style
293
294
```java
295
public class DebugJSONStyle extends JSONStyle {
296
297
public DebugJSONStyle() {
298
super(FLAG_PROTECT_KEYS | FLAG_PROTECT_VALUES);
299
}
300
301
@Override
302
public void objectStart(Appendable out) throws IOException {
303
out.append("{\n ");
304
}
305
306
@Override
307
public void objectStop(Appendable out) throws IOException {
308
out.append("\n}");
309
}
310
311
@Override
312
public void objectNext(Appendable out) throws IOException {
313
out.append(",\n ");
314
}
315
316
@Override
317
public void objectEndOfKey(Appendable out) throws IOException {
318
out.append(" : ");
319
}
320
321
@Override
322
public void arrayStart(Appendable out) throws IOException {
323
out.append("[\n ");
324
}
325
326
@Override
327
public void arrayStop(Appendable out) throws IOException {
328
out.append("\n ]");
329
}
330
331
@Override
332
public void arrayNextElm(Appendable out) throws IOException {
333
out.append(",\n ");
334
}
335
}
336
337
// Usage
338
JSONStyle debugStyle = new DebugJSONStyle();
339
JSONObject obj = new JSONObject()
340
.appendField("name", "John")
341
.appendField("items", Arrays.asList("a", "b", "c"));
342
343
String formatted = obj.toJSONString(debugStyle);
344
/*
345
{
346
"name" : "John",
347
"items" : [
348
"a",
349
"b",
350
"c"
351
]
352
}
353
*/
354
```
355
356
## Parser Configuration
357
358
While JSONStyle controls output formatting, parser configuration is handled through JSONParser mode flags.
359
360
### Common Parser Configurations
361
362
```java
363
// Strict web API parsing
364
int webApiMode = JSONParser.MODE_RFC4627 | JSONParser.REJECT_127_CHAR;
365
JSONParser webParser = new JSONParser(webApiMode);
366
367
// Lenient file parsing
368
int fileMode = JSONParser.MODE_PERMISSIVE |
369
JSONParser.ACCEPT_SIMPLE_QUOTE |
370
JSONParser.ACCEPT_USELESS_COMMA;
371
JSONParser fileParser = new JSONParser(fileMode);
372
373
// High-precision financial parsing
374
int financialMode = JSONParser.MODE_PERMISSIVE |
375
JSONParser.USE_HI_PRECISION_FLOAT |
376
JSONParser.BIG_DIGIT_UNRESTRICTED;
377
JSONParser financialParser = new JSONParser(financialMode);
378
```
379
380
### Configuration Validation
381
382
```java
383
public class ConfigurationValidator {
384
385
public static void validateStyleConfiguration(JSONStyle style) {
386
System.out.println("Style Configuration:");
387
System.out.println(" Protect Keys: " + style.protectKeys());
388
System.out.println(" Protect Values: " + style.protectValues());
389
System.out.println(" Web Safe: " + style.protect4Web());
390
System.out.println(" Ignore Null: " + style.ignoreNull());
391
System.out.println(" Indent: " + style.indent());
392
}
393
394
public static void testStyleOutput(JSONStyle style) {
395
JSONObject testObj = new JSONObject()
396
.appendField("simpleKey", "simpleValue")
397
.appendField("key with spaces", "value with \"quotes\"")
398
.appendField("nullValue", null)
399
.appendField("number", 42)
400
.appendField("htmlContent", "<script>alert('test')</script>");
401
402
String output = testObj.toJSONString(style);
403
System.out.println("Output: " + output);
404
System.out.println("Length: " + output.length());
405
}
406
}
407
408
// Usage
409
JSONStyle customStyle = new JSONStyle(
410
JSONStyle.FLAG_PROTECT_KEYS |
411
JSONStyle.FLAG_IGNORE_NULL |
412
JSONStyle.FLAG_PROTECT_4WEB
413
);
414
415
ConfigurationValidator.validateStyleConfiguration(customStyle);
416
ConfigurationValidator.testStyleOutput(customStyle);
417
```
418
419
## Performance Considerations
420
421
### Style Selection for Performance
422
423
```java
424
// Fastest serialization - minimal processing
425
JSONStyle fastest = JSONStyle.MAX_COMPRESS;
426
427
// Memory efficient - excludes nulls
428
JSONStyle memoryEfficient = new JSONStyle(JSONStyle.FLAG_IGNORE_NULL);
429
430
// Network efficient - maximum compression + null exclusion
431
JSONStyle networkEfficient = new JSONStyle(
432
JSONStyle.FLAG_AGRESSIVE | JSONStyle.FLAG_IGNORE_NULL
433
);
434
435
// Benchmark different styles
436
public void benchmarkStyles(Object testData, int iterations) {
437
JSONStyle[] styles = {
438
JSONStyle.NO_COMPRESS,
439
JSONStyle.LT_COMPRESS,
440
JSONStyle.MAX_COMPRESS,
441
networkEfficient
442
};
443
444
for (JSONStyle style : styles) {
445
long start = System.nanoTime();
446
for (int i = 0; i < iterations; i++) {
447
String json = JSONValue.toJSONString(testData, style);
448
}
449
long end = System.nanoTime();
450
451
String sample = JSONValue.toJSONString(testData, style);
452
System.out.printf("Style: %s, Time: %dms, Size: %d bytes%n",
453
style.getClass().getSimpleName(),
454
(end - start) / 1_000_000,
455
sample.length());
456
}
457
}
458
```
459
460
### Configuration Caching
461
462
```java
463
public class StyleCache {
464
private static final Map<String, JSONStyle> STYLE_CACHE = new ConcurrentHashMap<>();
465
466
public static JSONStyle getOrCreateStyle(String name, int flags) {
467
return STYLE_CACHE.computeIfAbsent(name, k -> new JSONStyle(flags));
468
}
469
470
// Predefined cached styles
471
public static final JSONStyle WEB_API_STYLE = getOrCreateStyle("webApi",
472
JSONStyle.FLAG_PROTECT_KEYS | JSONStyle.FLAG_PROTECT_4WEB | JSONStyle.FLAG_IGNORE_NULL);
473
474
public static final JSONStyle MOBILE_API_STYLE = getOrCreateStyle("mobileApi",
475
JSONStyle.FLAG_AGRESSIVE | JSONStyle.FLAG_IGNORE_NULL);
476
477
public static final JSONStyle DEBUG_STYLE = getOrCreateStyle("debug",
478
JSONStyle.FLAG_PROTECT_KEYS | JSONStyle.FLAG_PROTECT_VALUES);
479
}
480
481
// Usage
482
String webJson = JSONValue.toJSONString(data, StyleCache.WEB_API_STYLE);
483
String mobileJson = JSONValue.toJSONString(data, StyleCache.MOBILE_API_STYLE);
484
```
485
486
## Complete Configuration Examples
487
488
### REST API Configuration
489
490
```java
491
public class RestApiConfig {
492
// Input parsing - strict but allow common relaxations
493
private static final int API_PARSER_MODE =
494
JSONParser.MODE_RFC4627 |
495
JSONParser.ACCEPT_TAILLING_SPACE |
496
JSONParser.USE_INTEGER_STORAGE;
497
498
// Output formatting - web-safe and compact
499
private static final JSONStyle API_OUTPUT_STYLE = new JSONStyle(
500
JSONStyle.FLAG_PROTECT_KEYS |
501
JSONStyle.FLAG_PROTECT_4WEB |
502
JSONStyle.FLAG_IGNORE_NULL
503
);
504
505
public static final JSONParser API_PARSER = new JSONParser(API_PARSER_MODE);
506
507
public static <T> T parseRequest(String json, Class<T> type) throws ParseException {
508
return API_PARSER.parse(json, type);
509
}
510
511
public static String formatResponse(Object data) {
512
return JSONValue.toJSONString(data, API_OUTPUT_STYLE);
513
}
514
}
515
516
// Usage
517
try {
518
MyRequest request = RestApiConfig.parseRequest(requestJson, MyRequest.class);
519
MyResponse response = processRequest(request);
520
String responseJson = RestApiConfig.formatResponse(response);
521
return responseJson;
522
} catch (ParseException e) {
523
String errorJson = RestApiConfig.formatResponse(
524
Map.of("error", "Invalid JSON", "details", e.getMessage())
525
);
526
return errorJson;
527
}
528
```
529
530
### File Processing Configuration
531
532
```java
533
public class FileProcessingConfig {
534
// Lenient parsing for user-generated files
535
private static final int FILE_PARSER_MODE =
536
JSONParser.MODE_PERMISSIVE |
537
JSONParser.ACCEPT_SIMPLE_QUOTE |
538
JSONParser.ACCEPT_USELESS_COMMA |
539
JSONParser.ACCEPT_LEADING_ZERO |
540
JSONParser.IGNORE_CONTROL_CHAR;
541
542
// Readable output for file generation
543
private static final JSONStyle FILE_OUTPUT_STYLE = JSONStyle.NO_COMPRESS;
544
545
public static final JSONParser FILE_PARSER = new JSONParser(FILE_PARSER_MODE);
546
547
public static Object parseFile(Path filePath) throws IOException, ParseException {
548
try (Reader reader = Files.newBufferedReader(filePath)) {
549
return FILE_PARSER.parse(reader);
550
}
551
}
552
553
public static void writeFile(Object data, Path filePath) throws IOException {
554
try (Writer writer = Files.newBufferedWriter(filePath)) {
555
JSONValue.writeJSONString(data, writer, FILE_OUTPUT_STYLE);
556
}
557
}
558
}
559
```
560
561
### Configuration Testing Utility
562
563
```java
564
public class ConfigurationTester {
565
566
public static void testConfiguration(String name, JSONParser parser, JSONStyle style) {
567
System.out.println("Testing configuration: " + name);
568
569
// Test various JSON inputs
570
String[] testInputs = {
571
"{\"valid\": \"json\"}",
572
"{'single': 'quotes'}",
573
"{\"trailing\": \"comma\",}",
574
"{\"leading\": 007}",
575
"{\"unicode\": \"\\u0041\"}",
576
"{\"null\": null}",
577
"{\"number\": 123.456789012345678901234567890}"
578
};
579
580
for (String input : testInputs) {
581
try {
582
Object parsed = parser.parse(input);
583
String output = JSONValue.toJSONString(parsed, style);
584
System.out.printf(" ✓ %s -> %s%n", input, output);
585
} catch (ParseException e) {
586
System.out.printf(" ✗ %s -> ERROR: %s%n", input, e.getMessage());
587
}
588
}
589
590
System.out.println();
591
}
592
593
public static void main(String[] args) {
594
// Test different configurations
595
testConfiguration("Strict Web API",
596
new JSONParser(JSONParser.MODE_RFC4627),
597
new JSONStyle(JSONStyle.FLAG_PROTECT_KEYS | JSONStyle.FLAG_PROTECT_4WEB));
598
599
testConfiguration("Lenient File Processing",
600
new JSONParser(JSONParser.MODE_PERMISSIVE),
601
JSONStyle.NO_COMPRESS);
602
603
testConfiguration("High Performance API",
604
new JSONParser(JSONParser.MODE_PERMISSIVE),
605
JSONStyle.MAX_COMPRESS);
606
}
607
}
608
```