0
# Utilities & Extensions
1
2
Utility classes for string escaping, performance optimization, and error handling in JSON processing workflows.
3
4
## Capabilities
5
6
### StringEscapeUtils
7
8
Utility class providing string escaping and unescaping methods for Java and JavaScript contexts.
9
10
```java { .api }
11
/**
12
* Utility class for string escaping and unescaping operations
13
*/
14
public class StringEscapeUtils {
15
/** Default constructor */
16
public StringEscapeUtils();
17
18
/** Escape string for Java context */
19
public static String escapeJava(String str);
20
public static void escapeJava(Writer out, String str) throws IOException;
21
22
/** Escape string for JavaScript context */
23
public static String escapeJavaScript(String str);
24
public static void escapeJavaScript(Writer out, String str) throws IOException;
25
26
/** Unescape Java-escaped string */
27
public static String unescapeJava(String str);
28
public static void unescapeJava(Writer out, String str) throws IOException;
29
30
/** Unescape JavaScript-escaped string */
31
public static String unescapeJavaScript(String str);
32
public static void unescapeJavaScript(Writer out, String str) throws IOException;
33
}
34
```
35
36
**Usage Examples:**
37
38
```java
39
import groovy.json.StringEscapeUtils;
40
import java.io.StringWriter;
41
42
// Java string escaping
43
String original = "Hello \"World\"\nNew line\tTab";
44
String escaped = StringEscapeUtils.escapeJava(original);
45
// Result: "Hello \\\"World\\\"\\nNew line\\tTab"
46
47
String unescaped = StringEscapeUtils.unescapeJava(escaped);
48
// Result: "Hello \"World\"\nNew line\tTab"
49
50
// JavaScript string escaping
51
String jsString = "alert('Hello');\n<script>";
52
String jsEscaped = StringEscapeUtils.escapeJavaScript(jsString);
53
// Result: "alert(\\'Hello\\');\\n\\u003Cscript\\u003E"
54
55
// Stream-based escaping for large strings
56
StringWriter writer = new StringWriter();
57
StringEscapeUtils.escapeJava(writer, largeString);
58
String result = writer.toString();
59
60
// Common escaping scenarios
61
public class JsonStringProcessor {
62
public static String prepareForJson(String input) {
63
return StringEscapeUtils.escapeJavaScript(input);
64
}
65
66
public static String extractFromJson(String jsonString) {
67
return StringEscapeUtils.unescapeJavaScript(jsonString);
68
}
69
70
public static void writeEscapedToFile(String content, Writer fileWriter) throws IOException {
71
StringEscapeUtils.escapeJava(fileWriter, content);
72
}
73
}
74
```
75
76
### JsonException
77
78
Runtime exception class for JSON processing errors with comprehensive error information.
79
80
```java { .api }
81
/**
82
* Runtime exception for JSON processing errors
83
*/
84
public class JsonException extends RuntimeException {
85
/** Default constructor */
86
public JsonException();
87
88
/** Constructor with error message */
89
public JsonException(String message);
90
91
/** Constructor with message and cause */
92
public JsonException(String message, Throwable cause);
93
94
/** Constructor with cause only */
95
public JsonException(Throwable cause);
96
}
97
```
98
99
**Usage Examples:**
100
101
```java
102
import groovy.json.JsonException;
103
import groovy.json.JsonSlurper;
104
105
// Basic exception handling
106
try {
107
JsonSlurper slurper = new JsonSlurper();
108
Object result = slurper.parseText("invalid json");
109
} catch (JsonException e) {
110
System.err.println("JSON parsing failed: " + e.getMessage());
111
e.printStackTrace();
112
}
113
114
// Custom exception throwing
115
public class JsonValidator {
116
public static void validateJsonStructure(String json) throws JsonException {
117
if (json == null || json.trim().isEmpty()) {
118
throw new JsonException("JSON input cannot be null or empty");
119
}
120
121
if (!json.trim().startsWith("{") && !json.trim().startsWith("[")) {
122
throw new JsonException("JSON must start with '{' or '['");
123
}
124
125
try {
126
new JsonSlurper().parseText(json);
127
} catch (Exception e) {
128
throw new JsonException("Invalid JSON structure", e);
129
}
130
}
131
}
132
133
// Exception wrapping for custom processing
134
try {
135
processComplexJsonOperation();
136
} catch (IOException e) {
137
throw new JsonException("I/O error during JSON processing", e);
138
} catch (IllegalArgumentException e) {
139
throw new JsonException("Invalid argument in JSON processing", e);
140
}
141
```
142
143
### FastStringService Interface
144
145
Performance optimization interface for efficient string operations in JSON processing.
146
147
```java { .api }
148
/**
149
* Interface for optimized string operations
150
*/
151
public interface FastStringService {
152
/** Convert string to character array efficiently */
153
char[] toCharArray(String string);
154
155
/** Create string from character array without copying when possible */
156
String noCopyStringFromChars(char[] chars);
157
}
158
```
159
160
### FastStringServiceFactory Interface
161
162
Factory interface for creating FastStringService instances.
163
164
```java { .api }
165
/**
166
* Factory interface for FastStringService instances
167
*/
168
public interface FastStringServiceFactory {
169
/** Get FastStringService instance */
170
FastStringService getService();
171
}
172
```
173
174
### DefaultFastStringService
175
176
Default implementation of FastStringService providing optimized string operations.
177
178
```java { .api }
179
/**
180
* Default implementation of FastStringService
181
*/
182
public class DefaultFastStringService implements FastStringService {
183
/** Convert string to character array (implements FastStringService) */
184
public char[] toCharArray(String string);
185
186
/** Create string from character array without copying (implements FastStringService) */
187
public String noCopyStringFromChars(char[] chars);
188
}
189
```
190
191
### DefaultFastStringServiceFactory
192
193
Default factory implementation for creating FastStringService instances.
194
195
```java { .api }
196
/**
197
* Default factory implementation for FastStringService
198
*/
199
public class DefaultFastStringServiceFactory implements FastStringServiceFactory {
200
/** Get DefaultFastStringService instance (implements FastStringServiceFactory) */
201
public FastStringService getService();
202
}
203
```
204
205
**Usage Examples:**
206
207
```java
208
import org.apache.groovy.json.FastStringService;
209
import org.apache.groovy.json.DefaultFastStringServiceFactory;
210
211
// High-performance string operations
212
FastStringServiceFactory factory = new DefaultFastStringServiceFactory();
213
FastStringService stringService = factory.getService();
214
215
// Efficient string to char array conversion
216
String jsonData = loadLargeJsonString();
217
char[] chars = stringService.toCharArray(jsonData);
218
219
// Process character array directly
220
processJsonChars(chars);
221
222
// Convert back to string efficiently
223
String processed = stringService.noCopyStringFromChars(chars);
224
225
// Custom JSON processor using FastStringService
226
public class HighPerformanceJsonProcessor {
227
private final FastStringService stringService;
228
229
public HighPerformanceJsonProcessor() {
230
this.stringService = new DefaultFastStringServiceFactory().getService();
231
}
232
233
public String processJsonString(String json) {
234
// Convert to char array for processing
235
char[] chars = stringService.toCharArray(json);
236
237
// Perform in-place modifications
238
for (int i = 0; i < chars.length; i++) {
239
if (chars[i] == '\t') chars[i] = ' '; // Replace tabs with spaces
240
}
241
242
// Convert back without unnecessary copying
243
return stringService.noCopyStringFromChars(chars);
244
}
245
}
246
```
247
248
## Advanced Utility Patterns
249
250
### Comprehensive Error Handling Strategy
251
252
```java
253
public class RobustJsonProcessor {
254
private static final Logger logger = LoggerFactory.getLogger(RobustJsonProcessor.class);
255
256
public static class JsonProcessingResult {
257
private final Object data;
258
private final List<String> warnings;
259
private final boolean success;
260
261
public JsonProcessingResult(Object data, List<String> warnings, boolean success) {
262
this.data = data;
263
this.warnings = warnings;
264
this.success = success;
265
}
266
267
// Getters
268
public Object getData() { return data; }
269
public List<String> getWarnings() { return warnings; }
270
public boolean isSuccess() { return success; }
271
}
272
273
public static JsonProcessingResult safeParseJson(String json) {
274
List<String> warnings = new ArrayList<>();
275
276
if (json == null) {
277
return new JsonProcessingResult(null,
278
Arrays.asList("Input JSON is null"), false);
279
}
280
281
if (json.trim().isEmpty()) {
282
return new JsonProcessingResult(null,
283
Arrays.asList("Input JSON is empty"), false);
284
}
285
286
try {
287
// Attempt to clean and fix common JSON issues
288
String cleanedJson = cleanJsonString(json, warnings);
289
290
JsonSlurper slurper = new JsonSlurper();
291
Object result = slurper.parseText(cleanedJson);
292
293
return new JsonProcessingResult(result, warnings, true);
294
295
} catch (JsonException e) {
296
logger.error("JSON parsing failed", e);
297
warnings.add("Parse error: " + e.getMessage());
298
return new JsonProcessingResult(null, warnings, false);
299
} catch (Exception e) {
300
logger.error("Unexpected error during JSON parsing", e);
301
warnings.add("Unexpected error: " + e.getMessage());
302
return new JsonProcessingResult(null, warnings, false);
303
}
304
}
305
306
private static String cleanJsonString(String json, List<String> warnings) {
307
String cleaned = json;
308
309
// Remove BOM if present
310
if (cleaned.startsWith("\uFEFF")) {
311
cleaned = cleaned.substring(1);
312
warnings.add("Removed BOM from JSON input");
313
}
314
315
// Fix common quote issues
316
if (cleaned.contains("'") && !cleaned.contains("\"")) {
317
cleaned = cleaned.replace("'", "\"");
318
warnings.add("Converted single quotes to double quotes");
319
}
320
321
return cleaned;
322
}
323
}
324
```
325
326
### Performance-Optimized String Processing
327
328
```java
329
public class OptimizedStringProcessor {
330
private final FastStringService stringService;
331
private final char[] reusableBuffer;
332
private static final int BUFFER_SIZE = 8192;
333
334
public OptimizedStringProcessor() {
335
this.stringService = new DefaultFastStringServiceFactory().getService();
336
this.reusableBuffer = new char[BUFFER_SIZE];
337
}
338
339
public String processLargeJsonString(String json) {
340
char[] chars = stringService.toCharArray(json);
341
342
// In-place processing to avoid additional allocations
343
int writeIndex = 0;
344
boolean inString = false;
345
boolean escaped = false;
346
347
for (int i = 0; i < chars.length; i++) {
348
char c = chars[i];
349
350
if (!inString && Character.isWhitespace(c)) {
351
// Skip whitespace outside strings
352
continue;
353
}
354
355
if (c == '"' && !escaped) {
356
inString = !inString;
357
}
358
359
escaped = (c == '\\' && !escaped);
360
chars[writeIndex++] = c;
361
}
362
363
// Create new array with exact size needed
364
char[] result = new char[writeIndex];
365
System.arraycopy(chars, 0, result, 0, writeIndex);
366
367
return stringService.noCopyStringFromChars(result);
368
}
369
370
public List<String> extractStringLiterals(String json) {
371
List<String> literals = new ArrayList<>();
372
char[] chars = stringService.toCharArray(json);
373
374
StringBuilder current = new StringBuilder();
375
boolean inString = false;
376
boolean escaped = false;
377
378
for (char c : chars) {
379
if (c == '"' && !escaped) {
380
if (inString) {
381
literals.add(current.toString());
382
current.setLength(0);
383
}
384
inString = !inString;
385
} else if (inString) {
386
if (escaped || c != '\\') {
387
current.append(c);
388
}
389
}
390
391
escaped = (c == '\\' && !escaped);
392
}
393
394
return literals;
395
}
396
}
397
```
398
399
### Cross-Platform String Escaping
400
401
```java
402
public class CrossPlatformEscaping {
403
404
public static String escapeForPlatform(String input, Platform platform) {
405
switch (platform) {
406
case JAVA:
407
return StringEscapeUtils.escapeJava(input);
408
case JAVASCRIPT:
409
return StringEscapeUtils.escapeJavaScript(input);
410
case JSON:
411
// Use JSON-specific escaping
412
return escapeJsonString(input);
413
default:
414
return input;
415
}
416
}
417
418
public static String unescapeFromPlatform(String input, Platform platform) {
419
switch (platform) {
420
case JAVA:
421
return StringEscapeUtils.unescapeJava(input);
422
case JAVASCRIPT:
423
return StringEscapeUtils.unescapeJavaScript(input);
424
case JSON:
425
return unescapeJsonString(input);
426
default:
427
return input;
428
}
429
}
430
431
private static String escapeJsonString(String input) {
432
StringBuilder sb = new StringBuilder();
433
for (int i = 0; i < input.length(); i++) {
434
char c = input.charAt(i);
435
switch (c) {
436
case '"':
437
sb.append("\\\"");
438
break;
439
case '\\':
440
sb.append("\\\\");
441
break;
442
case '\b':
443
sb.append("\\b");
444
break;
445
case '\f':
446
sb.append("\\f");
447
break;
448
case '\n':
449
sb.append("\\n");
450
break;
451
case '\r':
452
sb.append("\\r");
453
break;
454
case '\t':
455
sb.append("\\t");
456
break;
457
default:
458
if (c < 0x20 || c > 0x7E) {
459
sb.append(String.format("\\u%04x", (int) c));
460
} else {
461
sb.append(c);
462
}
463
break;
464
}
465
}
466
return sb.toString();
467
}
468
469
private static String unescapeJsonString(String input) {
470
// Implementation for JSON-specific unescaping
471
return JsonLexer.unescape(input);
472
}
473
474
public enum Platform {
475
JAVA, JAVASCRIPT, JSON
476
}
477
}
478
```
479
480
## Error Recovery and Debugging
481
482
### JSON Debugging Utilities
483
484
```java
485
public class JsonDebugUtils {
486
487
public static String prettyPrintWithLineNumbers(String json) {
488
String[] lines = JsonOutput.prettyPrint(json).split("\n");
489
StringBuilder sb = new StringBuilder();
490
491
for (int i = 0; i < lines.length; i++) {
492
sb.append(String.format("%3d: %s%n", i + 1, lines[i]));
493
}
494
495
return sb.toString();
496
}
497
498
public static List<String> validateJsonStructure(String json) {
499
List<String> issues = new ArrayList<>();
500
501
try {
502
JsonLexer lexer = new JsonLexer(new StringReader(json));
503
int braceDepth = 0;
504
int bracketDepth = 0;
505
506
while (lexer.hasNext()) {
507
JsonToken token = lexer.next();
508
509
switch (token.getType()) {
510
case OPEN_BRACE:
511
braceDepth++;
512
break;
513
case CLOSE_BRACE:
514
braceDepth--;
515
if (braceDepth < 0) {
516
issues.add("Unmatched closing brace at line " + token.getStartLine());
517
}
518
break;
519
case OPEN_BRACKET:
520
bracketDepth++;
521
break;
522
case CLOSE_BRACKET:
523
bracketDepth--;
524
if (bracketDepth < 0) {
525
issues.add("Unmatched closing bracket at line " + token.getStartLine());
526
}
527
break;
528
}
529
}
530
531
if (braceDepth > 0) {
532
issues.add("Unclosed braces: " + braceDepth);
533
}
534
if (bracketDepth > 0) {
535
issues.add("Unclosed brackets: " + bracketDepth);
536
}
537
538
} catch (Exception e) {
539
issues.add("Parse error: " + e.getMessage());
540
}
541
542
return issues;
543
}
544
}
545
```