• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

javadev / underscore-java / #3107

pending completion
#3107

push

web-flow
Added com.github.underscore.XmlBuilder

4410 of 4410 relevant lines covered (100.0%)

1.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/main/java/com/github/underscore/Json.java
1
/*
2
 * The MIT License (MIT)
3
 *
4
 * Copyright 2015-2023 Valentyn Kolesnikov
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
package com.github.underscore;
25

26
import java.util.Collection;
27
import java.util.Iterator;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.StringJoiner;
31

32
@SuppressWarnings({"java:S3740", "java:S3776"})
33
public final class Json {
34
    private Json() {}
35

36
    private static final String NULL = "null";
37
    private static final String DIGIT = "digit";
38

39
    public static class JsonStringBuilder {
40
        public enum Step {
1✔
41
            TWO_SPACES(2),
1✔
42
            THREE_SPACES(3),
1✔
43
            FOUR_SPACES(4),
1✔
44
            COMPACT(0),
1✔
45
            TABS(1);
1✔
46
            private final int ident;
47

48
            Step(int ident) {
1✔
49
                this.ident = ident;
1✔
50
            }
1✔
51

52
            public int getIdent() {
53
                return ident;
1✔
54
            }
55
        }
56

57
        public enum Type {
1✔
58
            PURE("", "\n", "", "\""),
1✔
59
            JAVA("\"", "\\n\"\n + \"", "\";", "\\\"");
1✔
60
            private final String initial;
61
            private final String newLine;
62
            private final String tailLine;
63
            private final String wrapLine;
64

65
            Type(String initial, String newLine, String tailLine, String wrapLine) {
1✔
66
                this.initial = initial;
1✔
67
                this.newLine = newLine;
1✔
68
                this.tailLine = tailLine;
1✔
69
                this.wrapLine = wrapLine;
1✔
70
            }
1✔
71

72
            public String getInitial() {
73
                return initial;
1✔
74
            }
75

76
            public String getNewLine() {
77
                return newLine;
1✔
78
            }
79

80
            public String getTailLine() {
81
                return tailLine;
1✔
82
            }
83

84
            public String getWrapLine() {
85
                return wrapLine;
1✔
86
            }
87
        }
88

89
        private final StringJoiner builder;
90
        private final Step identStep;
91
        private final Type type;
92
        private int ident;
93

94
        public JsonStringBuilder(Step identStep) {
1✔
95
            builder = new StringJoiner("").add(Type.PURE.getInitial());
1✔
96
            this.identStep = identStep;
1✔
97
            this.type = Type.PURE;
1✔
98
        }
1✔
99

100
        public JsonStringBuilder(Type type) {
1✔
101
            builder = new StringJoiner("").add(type.getInitial());
1✔
102
            this.identStep = Step.TWO_SPACES;
1✔
103
            this.type = type;
1✔
104
        }
1✔
105

106
        public JsonStringBuilder() {
1✔
107
            builder = new StringJoiner("");
1✔
108
            this.identStep = Step.TWO_SPACES;
1✔
109
            this.type = Type.PURE;
1✔
110
        }
1✔
111

112
        public JsonStringBuilder append(final char character) {
113
            builder.add(String.valueOf(character));
1✔
114
            return this;
1✔
115
        }
116

117
        public JsonStringBuilder append(final String string) {
118
            builder.add(string);
1✔
119
            return this;
1✔
120
        }
121

122
        public JsonStringBuilder fillSpaces() {
123
            for (int index = 0; index < ident; index += 1) {
1✔
124
                builder.add(String.valueOf(identStep == Step.TABS ? '\t' : ' '));
1✔
125
            }
126
            return this;
1✔
127
        }
128

129
        public JsonStringBuilder incIdent() {
130
            ident += identStep.getIdent();
1✔
131
            return this;
1✔
132
        }
133

134
        public JsonStringBuilder decIdent() {
135
            ident -= identStep.getIdent();
1✔
136
            return this;
1✔
137
        }
138

139
        public JsonStringBuilder newLine() {
140
            if (identStep != Step.COMPACT) {
1✔
141
                builder.add(type.getNewLine());
1✔
142
            }
143
            return this;
1✔
144
        }
145

146
        public Step getIdentStep() {
147
            return identStep;
1✔
148
        }
149

150
        public String toString() {
151
            return builder.toString() + type.getTailLine();
1✔
152
        }
153
    }
154

155
    public static class JsonArray {
156
        private JsonArray() {}
157

158
        public static void writeJson(Collection collection, JsonStringBuilder builder) {
159
            if (collection == null) {
1✔
160
                builder.append(NULL);
1✔
161
                return;
1✔
162
            }
163

164
            Iterator iter = collection.iterator();
1✔
165

166
            builder.append('[').incIdent();
1✔
167
            if (!collection.isEmpty()) {
1✔
168
                builder.newLine();
1✔
169
            }
170
            while (iter.hasNext()) {
1✔
171
                Object value = iter.next();
1✔
172
                builder.fillSpaces();
1✔
173
                JsonValue.writeJson(value, builder);
1✔
174
                if (iter.hasNext()) {
1✔
175
                    builder.append(',').newLine();
1✔
176
                }
177
            }
1✔
178
            builder.newLine().decIdent().fillSpaces().append(']');
1✔
179
        }
1✔
180

181
        public static void writeJson(byte[] array, JsonStringBuilder builder) {
182
            if (array == null) {
1✔
183
                builder.append(NULL);
1✔
184
            } else if (array.length == 0) {
1✔
185
                builder.append("[]");
1✔
186
            } else {
187
                builder.append('[').incIdent().newLine();
1✔
188
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
189

190
                for (int i = 1; i < array.length; i++) {
1✔
191
                    builder.append(',').newLine().fillSpaces();
1✔
192
                    builder.append(String.valueOf(array[i]));
1✔
193
                }
194
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
195
            }
196
        }
1✔
197

198
        public static void writeJson(short[] array, JsonStringBuilder builder) {
199
            if (array == null) {
1✔
200
                builder.append(NULL);
1✔
201
            } else if (array.length == 0) {
1✔
202
                builder.append("[]");
1✔
203
            } else {
204
                builder.append('[').incIdent().newLine();
1✔
205
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
206

207
                for (int i = 1; i < array.length; i++) {
1✔
208
                    builder.append(',').newLine().fillSpaces();
1✔
209
                    builder.append(String.valueOf(array[i]));
1✔
210
                }
211
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
212
            }
213
        }
1✔
214

215
        public static void writeJson(int[] array, JsonStringBuilder builder) {
216
            if (array == null) {
1✔
217
                builder.append(NULL);
1✔
218
            } else if (array.length == 0) {
1✔
219
                builder.append("[]");
1✔
220
            } else {
221
                builder.append('[').incIdent().newLine();
1✔
222
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
223

224
                for (int i = 1; i < array.length; i++) {
1✔
225
                    builder.append(',').newLine().fillSpaces();
1✔
226
                    builder.append(String.valueOf(array[i]));
1✔
227
                }
228
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
229
            }
230
        }
1✔
231

232
        public static void writeJson(long[] array, JsonStringBuilder builder) {
233
            if (array == null) {
1✔
234
                builder.append(NULL);
1✔
235
            } else if (array.length == 0) {
1✔
236
                builder.append("[]");
1✔
237
            } else {
238
                builder.append('[').incIdent().newLine();
1✔
239
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
240

241
                for (int i = 1; i < array.length; i++) {
1✔
242
                    builder.append(',').newLine().fillSpaces();
1✔
243
                    builder.append(String.valueOf(array[i]));
1✔
244
                }
245
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
246
            }
247
        }
1✔
248

249
        public static void writeJson(float[] array, JsonStringBuilder builder) {
250
            if (array == null) {
1✔
251
                builder.append(NULL);
1✔
252
            } else if (array.length == 0) {
1✔
253
                builder.append("[]");
1✔
254
            } else {
255
                builder.append('[').incIdent().newLine();
1✔
256
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
257

258
                for (int i = 1; i < array.length; i++) {
1✔
259
                    builder.append(',').newLine().fillSpaces();
1✔
260
                    builder.append(String.valueOf(array[i]));
1✔
261
                }
262
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
263
            }
264
        }
1✔
265

266
        public static void writeJson(double[] array, JsonStringBuilder builder) {
267
            if (array == null) {
1✔
268
                builder.append(NULL);
1✔
269
            } else if (array.length == 0) {
1✔
270
                builder.append("[]");
1✔
271
            } else {
272
                builder.append('[').incIdent().newLine();
1✔
273
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
274

275
                for (int i = 1; i < array.length; i++) {
1✔
276
                    builder.append(',').newLine().fillSpaces();
1✔
277
                    builder.append(String.valueOf(array[i]));
1✔
278
                }
279
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
280
            }
281
        }
1✔
282

283
        public static void writeJson(boolean[] array, JsonStringBuilder builder) {
284
            if (array == null) {
1✔
285
                builder.append(NULL);
1✔
286
            } else if (array.length == 0) {
1✔
287
                builder.append("[]");
1✔
288
            } else {
289
                builder.append('[').incIdent().newLine();
1✔
290
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
291

292
                for (int i = 1; i < array.length; i++) {
1✔
293
                    builder.append(',').newLine().fillSpaces();
1✔
294
                    builder.append(String.valueOf(array[i]));
1✔
295
                }
296
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
297
            }
298
        }
1✔
299

300
        public static void writeJson(char[] array, JsonStringBuilder builder) {
301
            if (array == null) {
1✔
302
                builder.append(NULL);
1✔
303
            } else if (array.length == 0) {
1✔
304
                builder.append("[]");
1✔
305
            } else {
306
                builder.append('[').incIdent().newLine();
1✔
307
                builder.fillSpaces().append('\"').append(String.valueOf(array[0])).append('\"');
1✔
308

309
                for (int i = 1; i < array.length; i++) {
1✔
310
                    builder.append(',').newLine().fillSpaces();
1✔
311
                    builder.append('\"').append(String.valueOf(array[i])).append('\"');
1✔
312
                }
313
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
314
            }
315
        }
1✔
316

317
        public static void writeJson(Object[] array, JsonStringBuilder builder) {
318
            if (array == null) {
1✔
319
                builder.append(NULL);
1✔
320
            } else if (array.length == 0) {
1✔
321
                builder.append("[]");
1✔
322
            } else {
323
                builder.append('[').newLine().incIdent().fillSpaces();
1✔
324
                JsonValue.writeJson(array[0], builder);
1✔
325

326
                for (int i = 1; i < array.length; i++) {
1✔
327
                    builder.append(',').newLine().fillSpaces();
1✔
328
                    JsonValue.writeJson(array[i], builder);
1✔
329
                }
330
                builder.newLine().decIdent().fillSpaces().append(']');
1✔
331
            }
332
        }
1✔
333
    }
334

335
    public static class JsonObject {
336
        private JsonObject() {}
337

338
        public static void writeJson(Map map, JsonStringBuilder builder) {
339
            if (map == null) {
1✔
340
                builder.append(NULL);
1✔
341
                return;
1✔
342
            }
343
            Iterator iter = map.entrySet().iterator();
1✔
344
            builder.append('{').incIdent();
1✔
345
            if (!map.isEmpty()) {
1✔
346
                builder.newLine();
1✔
347
            }
348
            while (iter.hasNext()) {
1✔
349
                Map.Entry entry = (Map.Entry) iter.next();
1✔
350
                builder.fillSpaces().append(builder.type.getWrapLine());
1✔
351
                builder.append(JsonValue.escape(String.valueOf(entry.getKey())));
1✔
352
                builder.append(builder.type.getWrapLine());
1✔
353
                builder.append(':');
1✔
354
                if (builder.getIdentStep() != JsonStringBuilder.Step.COMPACT) {
1✔
355
                    builder.append(' ');
1✔
356
                }
357
                JsonValue.writeJson(entry.getValue(), builder);
1✔
358
                if (iter.hasNext()) {
1✔
359
                    builder.append(',').newLine();
1✔
360
                }
361
            }
1✔
362
            builder.newLine().decIdent().fillSpaces().append('}');
1✔
363
        }
1✔
364
    }
365

366
    public static class JsonValue {
367
        private JsonValue() {}
368

369
        public static void writeJson(Object value, JsonStringBuilder builder) {
370
            if (value == null) {
1✔
371
                builder.append(NULL);
1✔
372
            } else if (value instanceof String) {
1✔
373
                builder.append(builder.type.getWrapLine())
1✔
374
                        .append(escape((String) value))
1✔
375
                        .append(builder.type.getWrapLine());
1✔
376
            } else if (value instanceof Double) {
1✔
377
                if (((Double) value).isInfinite() || ((Double) value).isNaN()) {
1✔
378
                    builder.append(NULL);
1✔
379
                } else {
380
                    builder.append(value.toString());
1✔
381
                }
382
            } else if (value instanceof Float) {
1✔
383
                if (((Float) value).isInfinite() || ((Float) value).isNaN()) {
1✔
384
                    builder.append(NULL);
1✔
385
                } else {
386
                    builder.append(value.toString());
1✔
387
                }
388
            } else if (value instanceof Number) {
1✔
389
                builder.append(value.toString());
1✔
390
            } else if (value instanceof Boolean) {
1✔
391
                builder.append(value.toString());
1✔
392
            } else if (value instanceof Map) {
1✔
393
                JsonObject.writeJson((Map) value, builder);
1✔
394
            } else if (value instanceof Collection) {
1✔
395
                JsonArray.writeJson((Collection) value, builder);
1✔
396
            } else {
397
                doWriteJson(value, builder);
1✔
398
            }
399
        }
1✔
400

401
        private static void doWriteJson(Object value, JsonStringBuilder builder) {
402
            if (value instanceof byte[]) {
1✔
403
                JsonArray.writeJson((byte[]) value, builder);
1✔
404
            } else if (value instanceof short[]) {
1✔
405
                JsonArray.writeJson((short[]) value, builder);
1✔
406
            } else if (value instanceof int[]) {
1✔
407
                JsonArray.writeJson((int[]) value, builder);
1✔
408
            } else if (value instanceof long[]) {
1✔
409
                JsonArray.writeJson((long[]) value, builder);
1✔
410
            } else if (value instanceof float[]) {
1✔
411
                JsonArray.writeJson((float[]) value, builder);
1✔
412
            } else if (value instanceof double[]) {
1✔
413
                JsonArray.writeJson((double[]) value, builder);
1✔
414
            } else if (value instanceof boolean[]) {
1✔
415
                JsonArray.writeJson((boolean[]) value, builder);
1✔
416
            } else if (value instanceof char[]) {
1✔
417
                JsonArray.writeJson((char[]) value, builder);
1✔
418
            } else if (value instanceof Object[]) {
1✔
419
                JsonArray.writeJson((Object[]) value, builder);
1✔
420
            } else {
421
                builder.append(value.toString());
1✔
422
            }
423
        }
1✔
424

425
        public static String escape(String s) {
426
            if (s == null) {
1✔
427
                return null;
1✔
428
            }
429
            StringJoiner sb = new StringJoiner("");
1✔
430
            escape(s, sb);
1✔
431
            return sb.toString();
1✔
432
        }
433

434
        private static void escape(String s, StringJoiner sb) {
435
            final int len = s.length();
1✔
436
            for (int i = 0; i < len; i++) {
1✔
437
                char ch = s.charAt(i);
1✔
438
                switch (ch) {
1✔
439
                    case '"':
440
                        sb.add("\\\"");
1✔
441
                        break;
1✔
442
                    case '\\':
443
                        sb.add("\\\\");
1✔
444
                        break;
1✔
445
                    case '\b':
446
                        sb.add("\\b");
1✔
447
                        break;
1✔
448
                    case '\f':
449
                        sb.add("\\f");
1✔
450
                        break;
1✔
451
                    case '\n':
452
                        sb.add("\\n");
1✔
453
                        break;
1✔
454
                    case '\r':
455
                        sb.add("\\r");
1✔
456
                        break;
1✔
457
                    case '\t':
458
                        sb.add("\\t");
1✔
459
                        break;
1✔
460
                    case '€':
461
                        sb.add("€");
1✔
462
                        break;
1✔
463
                    default:
464
                        if (ch <= '\u001F'
1✔
465
                                || ch >= '\u007F' && ch <= '\u009F'
466
                                || ch >= '\u2000' && ch <= '\u20FF') {
467
                            String ss = Integer.toHexString(ch);
1✔
468
                            sb.add("\\u");
1✔
469
                            for (int k = 0; k < 4 - ss.length(); k++) {
1✔
470
                                sb.add("0");
1✔
471
                            }
472
                            sb.add(ss.toUpperCase());
1✔
473
                        } else {
1✔
474
                            sb.add(String.valueOf(ch));
1✔
475
                        }
476
                        break;
477
                }
478
            }
479
        }
1✔
480
    }
481

482
    public static class ParseException extends RuntimeException {
483
        private final int offset;
484
        private final int line;
485
        private final int column;
486

487
        public ParseException(String message, int offset, int line, int column) {
488
            super(message + " at " + line + ":" + column);
1✔
489
            this.offset = offset;
1✔
490
            this.line = line;
1✔
491
            this.column = column;
1✔
492
        }
1✔
493

494
        public int getOffset() {
495
            return offset;
1✔
496
        }
497

498
        public int getLine() {
499
            return line;
1✔
500
        }
501

502
        public int getColumn() {
503
            return column;
1✔
504
        }
505
    }
506

507
    public static class JsonParser {
508
        private final String json;
509
        private int index;
510
        private int line;
511
        private int lineOffset;
512
        private int current;
513
        private StringBuilder captureBuffer;
514
        private int captureStart;
515

516
        public JsonParser(String string) {
1✔
517
            this.json = string;
1✔
518
            line = 1;
1✔
519
            captureStart = -1;
1✔
520
        }
1✔
521

522
        public Object parse() {
523
            read();
1✔
524
            skipWhiteSpace();
1✔
525
            final Object result = readValue();
1✔
526
            skipWhiteSpace();
1✔
527
            if (!isEndOfText()) {
1✔
528
                throw error("Unexpected character");
1✔
529
            }
530
            return result;
1✔
531
        }
532

533
        private Object readValue() {
534
            switch (current) {
1✔
535
                case 'n':
536
                    return readNull();
1✔
537
                case 't':
538
                    return readTrue();
1✔
539
                case 'f':
540
                    return readFalse();
1✔
541
                case '"':
542
                    return readString();
1✔
543
                case '[':
544
                    return readArray();
1✔
545
                case '{':
546
                    return readObject();
1✔
547
                case '-':
548
                case '0':
549
                case '1':
550
                case '2':
551
                case '3':
552
                case '4':
553
                case '5':
554
                case '6':
555
                case '7':
556
                case '8':
557
                case '9':
558
                    return readNumber();
1✔
559
                default:
560
                    throw expected("value");
1✔
561
            }
562
        }
563

564
        private List<Object> readArray() {
565
            read();
1✔
566
            List<Object> array = U.newArrayList();
1✔
567
            skipWhiteSpace();
1✔
568
            if (readChar(']')) {
1✔
569
                return array;
1✔
570
            }
571
            do {
572
                skipWhiteSpace();
1✔
573
                array.add(readValue());
1✔
574
                skipWhiteSpace();
1✔
575
            } while (readChar(','));
1✔
576
            if (!readChar(']')) {
1✔
577
                throw expected("',' or ']'");
1✔
578
            }
579
            return array;
1✔
580
        }
581

582
        private Map<String, Object> readObject() {
583
            read();
1✔
584
            Map<String, Object> object = U.newLinkedHashMap();
1✔
585
            skipWhiteSpace();
1✔
586
            if (readChar('}')) {
1✔
587
                return object;
1✔
588
            }
589
            do {
590
                skipWhiteSpace();
1✔
591
                String name = readName();
1✔
592
                skipWhiteSpace();
1✔
593
                if (!readChar(':')) {
1✔
594
                    throw expected("':'");
1✔
595
                }
596
                skipWhiteSpace();
1✔
597
                object.put(name, readValue());
1✔
598
                skipWhiteSpace();
1✔
599
            } while (readChar(','));
1✔
600
            if (!readChar('}')) {
1✔
601
                throw expected("',' or '}'");
1✔
602
            }
603
            return object;
1✔
604
        }
605

606
        private String readName() {
607
            if (current != '"') {
1✔
608
                throw expected("name");
1✔
609
            }
610
            return readString();
1✔
611
        }
612

613
        private String readNull() {
614
            read();
1✔
615
            readRequiredChar('u');
1✔
616
            readRequiredChar('l');
1✔
617
            readRequiredChar('l');
1✔
618
            return null;
1✔
619
        }
620

621
        private Boolean readTrue() {
622
            read();
1✔
623
            readRequiredChar('r');
1✔
624
            readRequiredChar('u');
1✔
625
            readRequiredChar('e');
1✔
626
            return Boolean.TRUE;
1✔
627
        }
628

629
        private Boolean readFalse() {
630
            read();
1✔
631
            readRequiredChar('a');
1✔
632
            readRequiredChar('l');
1✔
633
            readRequiredChar('s');
1✔
634
            readRequiredChar('e');
1✔
635
            return Boolean.FALSE;
1✔
636
        }
637

638
        private void readRequiredChar(char ch) {
639
            if (!readChar(ch)) {
1✔
640
                throw expected("'" + ch + "'");
1✔
641
            }
642
        }
1✔
643

644
        private String readString() {
645
            read();
1✔
646
            startCapture();
1✔
647
            while (current != '"') {
1✔
648
                if (current == '\\') {
1✔
649
                    pauseCapture();
1✔
650
                    readEscape();
1✔
651
                    startCapture();
1✔
652
                } else if (current < 0x20) {
1✔
653
                    throw expected("valid string character");
1✔
654
                } else {
655
                    read();
1✔
656
                }
657
            }
658
            String string = endCapture();
1✔
659
            read();
1✔
660
            return string;
1✔
661
        }
662

663
        private void readEscape() {
664
            read();
1✔
665
            switch (current) {
1✔
666
                case '"':
667
                case '/':
668
                case '\\':
669
                    captureBuffer.append((char) current);
1✔
670
                    break;
1✔
671
                case 'b':
672
                    captureBuffer.append('\b');
1✔
673
                    break;
1✔
674
                case 'f':
675
                    captureBuffer.append('\f');
1✔
676
                    break;
1✔
677
                case 'n':
678
                    captureBuffer.append('\n');
1✔
679
                    break;
1✔
680
                case 'r':
681
                    captureBuffer.append('\r');
1✔
682
                    break;
1✔
683
                case 't':
684
                    captureBuffer.append('\t');
1✔
685
                    break;
1✔
686
                case 'u':
687
                    char[] hexChars = new char[4];
1✔
688
                    boolean isHexCharsDigits = true;
1✔
689
                    for (int i = 0; i < 4; i++) {
1✔
690
                        read();
1✔
691
                        if (!isHexDigit()) {
1✔
692
                            isHexCharsDigits = false;
1✔
693
                        }
694
                        hexChars[i] = (char) current;
1✔
695
                    }
696
                    if (isHexCharsDigits) {
1✔
697
                        captureBuffer.append((char) Integer.parseInt(new String(hexChars), 16));
1✔
698
                    } else {
699
                        captureBuffer
1✔
700
                                .append("\\u")
1✔
701
                                .append(hexChars[0])
1✔
702
                                .append(hexChars[1])
1✔
703
                                .append(hexChars[2])
1✔
704
                                .append(hexChars[3]);
1✔
705
                    }
706
                    break;
1✔
707
                default:
708
                    throw expected("valid escape sequence");
1✔
709
            }
710
            read();
1✔
711
        }
1✔
712

713
        private Number readNumber() {
714
            startCapture();
1✔
715
            readChar('-');
1✔
716
            int firstDigit = current;
1✔
717
            if (!readDigit()) {
1✔
718
                throw expected(DIGIT);
1✔
719
            }
720
            if (firstDigit != '0') {
1✔
721
                while (readDigit()) {
1✔
722
                    // ignored
723
                }
724
            }
725
            readFraction();
1✔
726
            readExponent();
1✔
727
            final String number = endCapture();
1✔
728
            final Number result;
729
            if (number.contains(".") || number.contains("e") || number.contains("E")) {
1✔
730
                if (number.length() > 9
1✔
731
                        || (number.contains(".") && number.length() - number.lastIndexOf('.') > 2)
1✔
732
                                && number.charAt(number.length() - 1) == '0') {
1✔
733
                    result = new java.math.BigDecimal(number);
1✔
734
                } else {
735
                    result = Double.valueOf(number);
1✔
736
                }
737
            } else {
738
                if (number.length() > 19) {
1✔
739
                    result = new java.math.BigInteger(number);
1✔
740
                } else {
741
                    result = Long.valueOf(number);
1✔
742
                }
743
            }
744
            return result;
1✔
745
        }
746

747
        private boolean readFraction() {
748
            if (!readChar('.')) {
1✔
749
                return false;
1✔
750
            }
751
            if (!readDigit()) {
1✔
752
                throw expected(DIGIT);
1✔
753
            }
754
            while (readDigit()) {
1✔
755
                // ignored
756
            }
757
            return true;
1✔
758
        }
759

760
        private boolean readExponent() {
761
            if (!readChar('e') && !readChar('E')) {
1✔
762
                return false;
1✔
763
            }
764
            if (!readChar('+')) {
1✔
765
                readChar('-');
1✔
766
            }
767
            if (!readDigit()) {
1✔
768
                throw expected(DIGIT);
1✔
769
            }
770
            while (readDigit()) {
1✔
771
                // ignored
772
            }
773
            return true;
1✔
774
        }
775

776
        private boolean readChar(char ch) {
777
            if (current != ch) {
1✔
778
                return false;
1✔
779
            }
780
            read();
1✔
781
            return true;
1✔
782
        }
783

784
        private boolean readDigit() {
785
            if (!isDigit()) {
1✔
786
                return false;
1✔
787
            }
788
            read();
1✔
789
            return true;
1✔
790
        }
791

792
        private void skipWhiteSpace() {
793
            while (isWhiteSpace()) {
1✔
794
                read();
1✔
795
            }
796
        }
1✔
797

798
        private void read() {
799
            if (index == json.length()) {
1✔
800
                current = -1;
1✔
801
                return;
1✔
802
            }
803
            if (current == '\n') {
1✔
804
                line++;
1✔
805
                lineOffset = index;
1✔
806
            }
807
            current = json.charAt(index++);
1✔
808
        }
1✔
809

810
        private void startCapture() {
811
            if (captureBuffer == null) {
1✔
812
                captureBuffer = new StringBuilder();
1✔
813
            }
814
            captureStart = index - 1;
1✔
815
        }
1✔
816

817
        private void pauseCapture() {
818
            captureBuffer.append(json, captureStart, index - 1);
1✔
819
            captureStart = -1;
1✔
820
        }
1✔
821

822
        private String endCapture() {
823
            int end = current == -1 ? index : index - 1;
1✔
824
            String captured;
825
            if (captureBuffer.length() > 0) {
1✔
826
                captureBuffer.append(json, captureStart, end);
1✔
827
                captured = captureBuffer.toString();
1✔
828
                captureBuffer.setLength(0);
1✔
829
            } else {
830
                captured = json.substring(captureStart, end);
1✔
831
            }
832
            captureStart = -1;
1✔
833
            return captured;
1✔
834
        }
835

836
        private ParseException expected(String expected) {
837
            if (isEndOfText()) {
1✔
838
                return error("Unexpected end of input");
1✔
839
            }
840
            return error("Expected " + expected);
1✔
841
        }
842

843
        private ParseException error(String message) {
844
            int absIndex = index;
1✔
845
            int column = absIndex - lineOffset;
1✔
846
            int offset = isEndOfText() ? absIndex : absIndex - 1;
1✔
847
            return new ParseException(message, offset, line, column - 1);
1✔
848
        }
849

850
        private boolean isWhiteSpace() {
851
            return current == ' ' || current == '\t' || current == '\n' || current == '\r';
1✔
852
        }
853

854
        private boolean isDigit() {
855
            return current >= '0' && current <= '9';
1✔
856
        }
857

858
        private boolean isHexDigit() {
859
            return isDigit()
1✔
860
                    || current >= 'a' && current <= 'f'
861
                    || current >= 'A' && current <= 'F';
862
        }
863

864
        private boolean isEndOfText() {
865
            return current == -1;
1✔
866
        }
867
    }
868

869
    public static String toJson(Collection collection, JsonStringBuilder.Step identStep) {
870
        final JsonStringBuilder builder = new JsonStringBuilder(identStep);
1✔
871

872
        JsonArray.writeJson(collection, builder);
1✔
873
        return builder.toString();
1✔
874
    }
875

876
    public static String toJson(Collection collection) {
877
        return toJson(collection, JsonStringBuilder.Step.TWO_SPACES);
1✔
878
    }
879

880
    public static String toJson(Map map, JsonStringBuilder.Step identStep) {
881
        final JsonStringBuilder builder = new JsonStringBuilder(identStep);
1✔
882

883
        JsonObject.writeJson(map, builder);
1✔
884
        return builder.toString();
1✔
885
    }
886

887
    public static String toJson(Map map) {
888
        return toJson(map, JsonStringBuilder.Step.TWO_SPACES);
1✔
889
    }
890

891
    public static String toJsonJavaString(Collection collection) {
892
        final JsonStringBuilder builder = new JsonStringBuilder(JsonStringBuilder.Type.JAVA);
1✔
893

894
        JsonArray.writeJson(collection, builder);
1✔
895
        return builder.toString();
1✔
896
    }
897

898
    public static String toJsonJavaString(Map map) {
899
        final JsonStringBuilder builder = new JsonStringBuilder(JsonStringBuilder.Type.JAVA);
1✔
900

901
        JsonObject.writeJson(map, builder);
1✔
902
        return builder.toString();
1✔
903
    }
904

905
    public static Object fromJson(String string) {
906
        return new JsonParser(string).parse();
1✔
907
    }
908

909
    public static String formatJson(String json, JsonStringBuilder.Step identStep) {
910
        Object result = fromJson(json);
1✔
911
        if (result instanceof Map) {
1✔
912
            return toJson((Map) result, identStep);
1✔
913
        }
914
        return toJson((List) result, identStep);
1✔
915
    }
916

917
    public static String formatJson(String json) {
918
        return formatJson(json, JsonStringBuilder.Step.TWO_SPACES);
1✔
919
    }
920
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc