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

javadev / underscore-java / #3210

pending completion
#3210

push

web-flow
Bump maven-project-info-reports-plugin from 3.4.4 to 3.4.5

4359 of 4359 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.ArrayList;
27
import java.util.Collection;
28
import java.util.Iterator;
29
import java.util.LinkedHashMap;
30
import java.util.List;
31
import java.util.Map;
32

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

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

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

49
            Step(int indent) {
1✔
50
                this.indent = indent;
1✔
51
            }
1✔
52

53
            public int getIndent() {
54
                return indent;
1✔
55
            }
56
        }
57

58
        private final StringBuilder builder;
59
        private final Step identStep;
60
        private int indent;
61

62
        public JsonStringBuilder(Step identStep) {
1✔
63
            builder = new StringBuilder();
1✔
64
            this.identStep = identStep;
1✔
65
        }
1✔
66

67
        public JsonStringBuilder() {
1✔
68
            builder = new StringBuilder();
1✔
69
            this.identStep = Step.TWO_SPACES;
1✔
70
        }
1✔
71

72
        public JsonStringBuilder append(final char character) {
73
            builder.append(character);
1✔
74
            return this;
1✔
75
        }
76

77
        public JsonStringBuilder append(final String string) {
78
            builder.append(string);
1✔
79
            return this;
1✔
80
        }
81

82
        public JsonStringBuilder fillSpaces() {
83
            for (int index = 0; index < indent; index += 1) {
1✔
84
                builder.append(identStep == Step.TABS ? '\t' : ' ');
1✔
85
            }
86
            return this;
1✔
87
        }
88

89
        public JsonStringBuilder incIndent() {
90
            indent += identStep.getIndent();
1✔
91
            return this;
1✔
92
        }
93

94
        public JsonStringBuilder decIndent() {
95
            indent -= identStep.getIndent();
1✔
96
            return this;
1✔
97
        }
98

99
        public JsonStringBuilder newLine() {
100
            if (identStep != Step.COMPACT) {
1✔
101
                builder.append('\n');
1✔
102
            }
103
            return this;
1✔
104
        }
105

106
        public Step getIdentStep() {
107
            return identStep;
1✔
108
        }
109

110
        public String toString() {
111
            return builder.toString();
1✔
112
        }
113
    }
114

115
    public static class JsonArray {
116
        private JsonArray() {}
117

118
        public static void writeJson(Collection collection, JsonStringBuilder builder) {
119
            if (collection == null) {
1✔
120
                builder.append(NULL);
1✔
121
                return;
1✔
122
            }
123
            Iterator iter = collection.iterator();
1✔
124
            builder.append('[').incIndent();
1✔
125
            if (!collection.isEmpty()) {
1✔
126
                builder.newLine();
1✔
127
            }
128
            while (iter.hasNext()) {
1✔
129
                Object value = iter.next();
1✔
130
                builder.fillSpaces();
1✔
131
                JsonValue.writeJson(value, builder);
1✔
132
                if (iter.hasNext()) {
1✔
133
                    builder.append(',').newLine();
1✔
134
                }
135
            }
1✔
136
            builder.newLine().decIndent().fillSpaces().append(']');
1✔
137
        }
1✔
138

139
        public static void writeJson(byte[] array, JsonStringBuilder builder) {
140
            if (array == null) {
1✔
141
                builder.append(NULL);
1✔
142
            } else if (array.length == 0) {
1✔
143
                builder.append("[]");
1✔
144
            } else {
145
                builder.append('[').incIndent().newLine();
1✔
146
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
147
                for (int i = 1; i < array.length; i++) {
1✔
148
                    builder.append(',').newLine().fillSpaces();
1✔
149
                    builder.append(String.valueOf(array[i]));
1✔
150
                }
151
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
152
            }
153
        }
1✔
154

155
        public static void writeJson(short[] array, JsonStringBuilder builder) {
156
            if (array == null) {
1✔
157
                builder.append(NULL);
1✔
158
            } else if (array.length == 0) {
1✔
159
                builder.append("[]");
1✔
160
            } else {
161
                builder.append('[').incIndent().newLine();
1✔
162
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
163
                for (int i = 1; i < array.length; i++) {
1✔
164
                    builder.append(',').newLine().fillSpaces();
1✔
165
                    builder.append(String.valueOf(array[i]));
1✔
166
                }
167
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
168
            }
169
        }
1✔
170

171
        public static void writeJson(int[] array, JsonStringBuilder builder) {
172
            if (array == null) {
1✔
173
                builder.append(NULL);
1✔
174
            } else if (array.length == 0) {
1✔
175
                builder.append("[]");
1✔
176
            } else {
177
                builder.append('[').incIndent().newLine();
1✔
178
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
179
                for (int i = 1; i < array.length; i++) {
1✔
180
                    builder.append(',').newLine().fillSpaces();
1✔
181
                    builder.append(String.valueOf(array[i]));
1✔
182
                }
183
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
184
            }
185
        }
1✔
186

187
        public static void writeJson(long[] array, JsonStringBuilder builder) {
188
            if (array == null) {
1✔
189
                builder.append(NULL);
1✔
190
            } else if (array.length == 0) {
1✔
191
                builder.append("[]");
1✔
192
            } else {
193
                builder.append('[').incIndent().newLine();
1✔
194
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
195
                for (int i = 1; i < array.length; i++) {
1✔
196
                    builder.append(',').newLine().fillSpaces();
1✔
197
                    builder.append(String.valueOf(array[i]));
1✔
198
                }
199
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
200
            }
201
        }
1✔
202

203
        public static void writeJson(float[] array, JsonStringBuilder builder) {
204
            if (array == null) {
1✔
205
                builder.append(NULL);
1✔
206
            } else if (array.length == 0) {
1✔
207
                builder.append("[]");
1✔
208
            } else {
209
                builder.append('[').incIndent().newLine();
1✔
210
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
211
                for (int i = 1; i < array.length; i++) {
1✔
212
                    builder.append(',').newLine().fillSpaces();
1✔
213
                    builder.append(String.valueOf(array[i]));
1✔
214
                }
215
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
216
            }
217
        }
1✔
218

219
        public static void writeJson(double[] array, JsonStringBuilder builder) {
220
            if (array == null) {
1✔
221
                builder.append(NULL);
1✔
222
            } else if (array.length == 0) {
1✔
223
                builder.append("[]");
1✔
224
            } else {
225
                builder.append('[').incIndent().newLine();
1✔
226
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
227
                for (int i = 1; i < array.length; i++) {
1✔
228
                    builder.append(',').newLine().fillSpaces();
1✔
229
                    builder.append(String.valueOf(array[i]));
1✔
230
                }
231
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
232
            }
233
        }
1✔
234

235
        public static void writeJson(boolean[] array, JsonStringBuilder builder) {
236
            if (array == null) {
1✔
237
                builder.append(NULL);
1✔
238
            } else if (array.length == 0) {
1✔
239
                builder.append("[]");
1✔
240
            } else {
241
                builder.append('[').incIndent().newLine();
1✔
242
                builder.fillSpaces().append(String.valueOf(array[0]));
1✔
243
                for (int i = 1; i < array.length; i++) {
1✔
244
                    builder.append(',').newLine().fillSpaces();
1✔
245
                    builder.append(String.valueOf(array[i]));
1✔
246
                }
247
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
248
            }
249
        }
1✔
250

251
        public static void writeJson(char[] array, JsonStringBuilder builder) {
252
            if (array == null) {
1✔
253
                builder.append(NULL);
1✔
254
            } else if (array.length == 0) {
1✔
255
                builder.append("[]");
1✔
256
            } else {
257
                builder.append('[').incIndent().newLine();
1✔
258
                builder.fillSpaces().append('\"').append(String.valueOf(array[0])).append('\"');
1✔
259
                for (int i = 1; i < array.length; i++) {
1✔
260
                    builder.append(',').newLine().fillSpaces();
1✔
261
                    builder.append('"').append(String.valueOf(array[i])).append('"');
1✔
262
                }
263
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
264
            }
265
        }
1✔
266

267
        public static void writeJson(Object[] array, JsonStringBuilder builder) {
268
            if (array == null) {
1✔
269
                builder.append(NULL);
1✔
270
            } else if (array.length == 0) {
1✔
271
                builder.append("[]");
1✔
272
            } else {
273
                builder.append('[').newLine().incIndent().fillSpaces();
1✔
274
                JsonValue.writeJson(array[0], builder);
1✔
275
                for (int i = 1; i < array.length; i++) {
1✔
276
                    builder.append(',').newLine().fillSpaces();
1✔
277
                    JsonValue.writeJson(array[i], builder);
1✔
278
                }
279
                builder.newLine().decIndent().fillSpaces().append(']');
1✔
280
            }
281
        }
1✔
282
    }
283

284
    public static class JsonObject {
285
        private JsonObject() {}
286

287
        public static void writeJson(Map map, JsonStringBuilder builder) {
288
            if (map == null) {
1✔
289
                builder.append(NULL);
1✔
290
                return;
1✔
291
            }
292
            Iterator iter = map.entrySet().iterator();
1✔
293
            builder.append('{').incIndent();
1✔
294
            if (!map.isEmpty()) {
1✔
295
                builder.newLine();
1✔
296
            }
297
            while (iter.hasNext()) {
1✔
298
                Map.Entry entry = (Map.Entry) iter.next();
1✔
299
                builder.fillSpaces().append('"');
1✔
300
                builder.append(JsonValue.escape(String.valueOf(entry.getKey())));
1✔
301
                builder.append('"');
1✔
302
                builder.append(':');
1✔
303
                if (builder.getIdentStep() != JsonStringBuilder.Step.COMPACT) {
1✔
304
                    builder.append(' ');
1✔
305
                }
306
                JsonValue.writeJson(entry.getValue(), builder);
1✔
307
                if (iter.hasNext()) {
1✔
308
                    builder.append(',').newLine();
1✔
309
                }
310
            }
1✔
311
            builder.newLine().decIndent().fillSpaces().append('}');
1✔
312
        }
1✔
313
    }
314

315
    public static class JsonValue {
316
        private JsonValue() {}
317

318
        public static void writeJson(Object value, JsonStringBuilder builder) {
319
            if (value == null) {
1✔
320
                builder.append(NULL);
1✔
321
            } else if (value instanceof String) {
1✔
322
                builder.append('"').append(escape((String) value)).append('"');
1✔
323
            } else if (value instanceof Double) {
1✔
324
                if (((Double) value).isInfinite() || ((Double) value).isNaN()) {
1✔
325
                    builder.append(NULL);
1✔
326
                } else {
327
                    builder.append(value.toString());
1✔
328
                }
329
            } else if (value instanceof Float) {
1✔
330
                if (((Float) value).isInfinite() || ((Float) value).isNaN()) {
1✔
331
                    builder.append(NULL);
1✔
332
                } else {
333
                    builder.append(value.toString());
1✔
334
                }
335
            } else if (value instanceof Number) {
1✔
336
                builder.append(value.toString());
1✔
337
            } else if (value instanceof Boolean) {
1✔
338
                builder.append(value.toString());
1✔
339
            } else if (value instanceof Map) {
1✔
340
                JsonObject.writeJson((Map) value, builder);
1✔
341
            } else if (value instanceof Collection) {
1✔
342
                JsonArray.writeJson((Collection) value, builder);
1✔
343
            } else {
344
                doWriteJson(value, builder);
1✔
345
            }
346
        }
1✔
347

348
        private static void doWriteJson(Object value, JsonStringBuilder builder) {
349
            if (value instanceof byte[]) {
1✔
350
                JsonArray.writeJson((byte[]) value, builder);
1✔
351
            } else if (value instanceof short[]) {
1✔
352
                JsonArray.writeJson((short[]) value, builder);
1✔
353
            } else if (value instanceof int[]) {
1✔
354
                JsonArray.writeJson((int[]) value, builder);
1✔
355
            } else if (value instanceof long[]) {
1✔
356
                JsonArray.writeJson((long[]) value, builder);
1✔
357
            } else if (value instanceof float[]) {
1✔
358
                JsonArray.writeJson((float[]) value, builder);
1✔
359
            } else if (value instanceof double[]) {
1✔
360
                JsonArray.writeJson((double[]) value, builder);
1✔
361
            } else if (value instanceof boolean[]) {
1✔
362
                JsonArray.writeJson((boolean[]) value, builder);
1✔
363
            } else if (value instanceof char[]) {
1✔
364
                JsonArray.writeJson((char[]) value, builder);
1✔
365
            } else if (value instanceof Object[]) {
1✔
366
                JsonArray.writeJson((Object[]) value, builder);
1✔
367
            } else {
368
                builder.append('"').append(escape(value.toString())).append('"');
1✔
369
            }
370
        }
1✔
371

372
        public static String escape(String s) {
373
            if (s == null) {
1✔
374
                return null;
1✔
375
            }
376
            StringBuilder sb = new StringBuilder();
1✔
377
            escape(s, sb);
1✔
378
            return sb.toString();
1✔
379
        }
380

381
        private static void escape(String s, StringBuilder sb) {
382
            final int len = s.length();
1✔
383
            for (int i = 0; i < len; i++) {
1✔
384
                char ch = s.charAt(i);
1✔
385
                switch (ch) {
1✔
386
                    case '"':
387
                        sb.append("\\\"");
1✔
388
                        break;
1✔
389
                    case '\\':
390
                        sb.append("\\\\");
1✔
391
                        break;
1✔
392
                    case '\b':
393
                        sb.append("\\b");
1✔
394
                        break;
1✔
395
                    case '\f':
396
                        sb.append("\\f");
1✔
397
                        break;
1✔
398
                    case '\n':
399
                        sb.append("\\n");
1✔
400
                        break;
1✔
401
                    case '\r':
402
                        sb.append("\\r");
1✔
403
                        break;
1✔
404
                    case '\t':
405
                        sb.append("\\t");
1✔
406
                        break;
1✔
407
                    case '€':
408
                        sb.append('€');
1✔
409
                        break;
1✔
410
                    default:
411
                        if (ch <= '\u001F'
1✔
412
                                || ch >= '\u007F' && ch <= '\u009F'
413
                                || ch >= '\u2000' && ch <= '\u20FF') {
414
                            String ss = Integer.toHexString(ch);
1✔
415
                            sb.append("\\u");
1✔
416
                            for (int k = 0; k < 4 - ss.length(); k++) {
1✔
417
                                sb.append("0");
1✔
418
                            }
419
                            sb.append(ss.toUpperCase());
1✔
420
                        } else {
1✔
421
                            sb.append(ch);
1✔
422
                        }
423
                        break;
424
                }
425
            }
426
        }
1✔
427
    }
428

429
    public static class ParseException extends RuntimeException {
430
        private final int offset;
431
        private final int line;
432
        private final int column;
433

434
        public ParseException(String message, int offset, int line, int column) {
435
            super(String.format("%s at %d:%d", message, line, column));
1✔
436
            this.offset = offset;
1✔
437
            this.line = line;
1✔
438
            this.column = column;
1✔
439
        }
1✔
440

441
        public int getOffset() {
442
            return offset;
1✔
443
        }
444

445
        public int getLine() {
446
            return line;
1✔
447
        }
448

449
        public int getColumn() {
450
            return column;
1✔
451
        }
452
    }
453

454
    public static class JsonParser {
455
        private final String json;
456
        private int index;
457
        private int line;
458
        private int lineOffset;
459
        private int current;
460
        private StringBuilder captureBuffer;
461
        private int captureStart;
462

463
        public JsonParser(String string) {
1✔
464
            this.json = string;
1✔
465
            line = 1;
1✔
466
            captureStart = -1;
1✔
467
        }
1✔
468

469
        public Object parse() {
470
            read();
1✔
471
            skipWhiteSpace();
1✔
472
            final Object result = readValue();
1✔
473
            skipWhiteSpace();
1✔
474
            if (!isEndOfText()) {
1✔
475
                throw error("Unexpected character");
1✔
476
            }
477
            return result;
1✔
478
        }
479

480
        private Object readValue() {
481
            switch (current) {
1✔
482
                case 'n':
483
                    return readNull();
1✔
484
                case 't':
485
                    return readTrue();
1✔
486
                case 'f':
487
                    return readFalse();
1✔
488
                case '"':
489
                    return readString();
1✔
490
                case '[':
491
                    return readArray();
1✔
492
                case '{':
493
                    return readObject();
1✔
494
                case '-':
495
                case '0':
496
                case '1':
497
                case '2':
498
                case '3':
499
                case '4':
500
                case '5':
501
                case '6':
502
                case '7':
503
                case '8':
504
                case '9':
505
                    return readNumber();
1✔
506
                default:
507
                    throw expected("value");
1✔
508
            }
509
        }
510

511
        private List<Object> readArray() {
512
            read();
1✔
513
            List<Object> array = new ArrayList<>();
1✔
514
            skipWhiteSpace();
1✔
515
            if (readChar(']')) {
1✔
516
                return array;
1✔
517
            }
518
            do {
519
                skipWhiteSpace();
1✔
520
                array.add(readValue());
1✔
521
                skipWhiteSpace();
1✔
522
            } while (readChar(','));
1✔
523
            if (!readChar(']')) {
1✔
524
                throw expected("',' or ']'");
1✔
525
            }
526
            return array;
1✔
527
        }
528

529
        private Map<String, Object> readObject() {
530
            read();
1✔
531
            Map<String, Object> object = new LinkedHashMap<>();
1✔
532
            skipWhiteSpace();
1✔
533
            if (readChar('}')) {
1✔
534
                return object;
1✔
535
            }
536
            do {
537
                skipWhiteSpace();
1✔
538
                String name = readName();
1✔
539
                skipWhiteSpace();
1✔
540
                if (!readChar(':')) {
1✔
541
                    throw expected("':'");
1✔
542
                }
543
                skipWhiteSpace();
1✔
544
                object.put(name, readValue());
1✔
545
                skipWhiteSpace();
1✔
546
            } while (readChar(','));
1✔
547
            if (!readChar('}')) {
1✔
548
                throw expected("',' or '}'");
1✔
549
            }
550
            return object;
1✔
551
        }
552

553
        private String readName() {
554
            if (current != '"') {
1✔
555
                throw expected("name");
1✔
556
            }
557
            return readString();
1✔
558
        }
559

560
        private String readNull() {
561
            read();
1✔
562
            readRequiredChar('u');
1✔
563
            readRequiredChar('l');
1✔
564
            readRequiredChar('l');
1✔
565
            return null;
1✔
566
        }
567

568
        private Boolean readTrue() {
569
            read();
1✔
570
            readRequiredChar('r');
1✔
571
            readRequiredChar('u');
1✔
572
            readRequiredChar('e');
1✔
573
            return Boolean.TRUE;
1✔
574
        }
575

576
        private Boolean readFalse() {
577
            read();
1✔
578
            readRequiredChar('a');
1✔
579
            readRequiredChar('l');
1✔
580
            readRequiredChar('s');
1✔
581
            readRequiredChar('e');
1✔
582
            return Boolean.FALSE;
1✔
583
        }
584

585
        private void readRequiredChar(char ch) {
586
            if (!readChar(ch)) {
1✔
587
                throw expected("'" + ch + "'");
1✔
588
            }
589
        }
1✔
590

591
        private String readString() {
592
            read();
1✔
593
            startCapture();
1✔
594
            while (current != '"') {
1✔
595
                if (current == '\\') {
1✔
596
                    pauseCapture();
1✔
597
                    readEscape();
1✔
598
                    startCapture();
1✔
599
                } else if (current < 0x20) {
1✔
600
                    throw expected("valid string character");
1✔
601
                } else {
602
                    read();
1✔
603
                }
604
            }
605
            String string = endCapture();
1✔
606
            read();
1✔
607
            return string;
1✔
608
        }
609

610
        private void readEscape() {
611
            read();
1✔
612
            switch (current) {
1✔
613
                case '"':
614
                case '/':
615
                case '\\':
616
                    captureBuffer.append((char) current);
1✔
617
                    break;
1✔
618
                case 'b':
619
                    captureBuffer.append('\b');
1✔
620
                    break;
1✔
621
                case 'f':
622
                    captureBuffer.append('\f');
1✔
623
                    break;
1✔
624
                case 'n':
625
                    captureBuffer.append('\n');
1✔
626
                    break;
1✔
627
                case 'r':
628
                    captureBuffer.append('\r');
1✔
629
                    break;
1✔
630
                case 't':
631
                    captureBuffer.append('\t');
1✔
632
                    break;
1✔
633
                case 'u':
634
                    char[] hexChars = new char[4];
1✔
635
                    boolean isHexCharsDigits = true;
1✔
636
                    for (int i = 0; i < 4; i++) {
1✔
637
                        read();
1✔
638
                        if (!isHexDigit()) {
1✔
639
                            isHexCharsDigits = false;
1✔
640
                        }
641
                        hexChars[i] = (char) current;
1✔
642
                    }
643
                    if (isHexCharsDigits) {
1✔
644
                        captureBuffer.append((char) Integer.parseInt(new String(hexChars), 16));
1✔
645
                    } else {
646
                        captureBuffer
1✔
647
                                .append("\\u")
1✔
648
                                .append(hexChars[0])
1✔
649
                                .append(hexChars[1])
1✔
650
                                .append(hexChars[2])
1✔
651
                                .append(hexChars[3]);
1✔
652
                    }
653
                    break;
1✔
654
                default:
655
                    throw expected("valid escape sequence");
1✔
656
            }
657
            read();
1✔
658
        }
1✔
659

660
        private Number readNumber() {
661
            startCapture();
1✔
662
            readChar('-');
1✔
663
            int firstDigit = current;
1✔
664
            if (!readDigit()) {
1✔
665
                throw expected(DIGIT);
1✔
666
            }
667
            if (firstDigit != '0') {
1✔
668
                while (readDigit()) {
1✔
669
                    // ignored
670
                }
671
            }
672
            readFraction();
1✔
673
            readExponent();
1✔
674
            final String number = endCapture();
1✔
675
            final Number result;
676
            if (number.contains(".") || number.contains("e") || number.contains("E")) {
1✔
677
                if (number.length() > 9
1✔
678
                        || (number.contains(".") && number.length() - number.lastIndexOf('.') > 2)
1✔
679
                                && number.charAt(number.length() - 1) == '0') {
1✔
680
                    result = new java.math.BigDecimal(number);
1✔
681
                } else {
682
                    result = Double.valueOf(number);
1✔
683
                }
684
            } else {
685
                if (number.length() > 19) {
1✔
686
                    result = new java.math.BigInteger(number);
1✔
687
                } else {
688
                    result = Long.valueOf(number);
1✔
689
                }
690
            }
691
            return result;
1✔
692
        }
693

694
        private boolean readFraction() {
695
            if (!readChar('.')) {
1✔
696
                return false;
1✔
697
            }
698
            if (!readDigit()) {
1✔
699
                throw expected(DIGIT);
1✔
700
            }
701
            while (readDigit()) {
1✔
702
                // ignored
703
            }
704
            return true;
1✔
705
        }
706

707
        private boolean readExponent() {
708
            if (!readChar('e') && !readChar('E')) {
1✔
709
                return false;
1✔
710
            }
711
            if (!readChar('+')) {
1✔
712
                readChar('-');
1✔
713
            }
714
            if (!readDigit()) {
1✔
715
                throw expected(DIGIT);
1✔
716
            }
717
            while (readDigit()) {
1✔
718
                // ignored
719
            }
720
            return true;
1✔
721
        }
722

723
        private boolean readChar(char ch) {
724
            if (current != ch) {
1✔
725
                return false;
1✔
726
            }
727
            read();
1✔
728
            return true;
1✔
729
        }
730

731
        private boolean readDigit() {
732
            if (!isDigit()) {
1✔
733
                return false;
1✔
734
            }
735
            read();
1✔
736
            return true;
1✔
737
        }
738

739
        private void skipWhiteSpace() {
740
            while (isWhiteSpace()) {
1✔
741
                read();
1✔
742
            }
743
        }
1✔
744

745
        private void read() {
746
            if (index == json.length()) {
1✔
747
                current = -1;
1✔
748
                return;
1✔
749
            }
750
            if (current == '\n') {
1✔
751
                line++;
1✔
752
                lineOffset = index;
1✔
753
            }
754
            current = json.charAt(index++);
1✔
755
        }
1✔
756

757
        private void startCapture() {
758
            if (captureBuffer == null) {
1✔
759
                captureBuffer = new StringBuilder();
1✔
760
            }
761
            captureStart = index - 1;
1✔
762
        }
1✔
763

764
        private void pauseCapture() {
765
            captureBuffer.append(json, captureStart, index - 1);
1✔
766
            captureStart = -1;
1✔
767
        }
1✔
768

769
        private String endCapture() {
770
            int end = current == -1 ? index : index - 1;
1✔
771
            String captured;
772
            if (captureBuffer.length() > 0) {
1✔
773
                captureBuffer.append(json, captureStart, end);
1✔
774
                captured = captureBuffer.toString();
1✔
775
                captureBuffer.setLength(0);
1✔
776
            } else {
777
                captured = json.substring(captureStart, end);
1✔
778
            }
779
            captureStart = -1;
1✔
780
            return captured;
1✔
781
        }
782

783
        private ParseException expected(String expected) {
784
            if (isEndOfText()) {
1✔
785
                return error("Unexpected end of input");
1✔
786
            }
787
            return error("Expected " + expected);
1✔
788
        }
789

790
        private ParseException error(String message) {
791
            int absIndex = index;
1✔
792
            int column = absIndex - lineOffset;
1✔
793
            int offset = isEndOfText() ? absIndex : absIndex - 1;
1✔
794
            return new ParseException(message, offset, line, column - 1);
1✔
795
        }
796

797
        private boolean isWhiteSpace() {
798
            return current == ' ' || current == '\t' || current == '\n' || current == '\r';
1✔
799
        }
800

801
        private boolean isDigit() {
802
            return current >= '0' && current <= '9';
1✔
803
        }
804

805
        private boolean isHexDigit() {
806
            return isDigit()
1✔
807
                    || current >= 'a' && current <= 'f'
808
                    || current >= 'A' && current <= 'F';
809
        }
810

811
        private boolean isEndOfText() {
812
            return current == -1;
1✔
813
        }
814
    }
815

816
    public static String toJson(Collection collection, JsonStringBuilder.Step identStep) {
817
        final JsonStringBuilder builder = new JsonStringBuilder(identStep);
1✔
818
        JsonArray.writeJson(collection, builder);
1✔
819
        return builder.toString();
1✔
820
    }
821

822
    public static String toJson(Collection collection) {
823
        return toJson(collection, JsonStringBuilder.Step.TWO_SPACES);
1✔
824
    }
825

826
    public static String toJson(Map map, JsonStringBuilder.Step identStep) {
827
        final JsonStringBuilder builder = new JsonStringBuilder(identStep);
1✔
828
        JsonObject.writeJson(map, builder);
1✔
829
        return builder.toString();
1✔
830
    }
831

832
    public static String toJson(Map map) {
833
        return toJson(map, JsonStringBuilder.Step.TWO_SPACES);
1✔
834
    }
835

836
    public static Object fromJson(String string) {
837
        return new JsonParser(string).parse();
1✔
838
    }
839

840
    public static String formatJson(String json, JsonStringBuilder.Step identStep) {
841
        Object result = fromJson(json);
1✔
842
        if (result instanceof Map) {
1✔
843
            return toJson((Map) result, identStep);
1✔
844
        }
845
        return toJson((List) result, identStep);
1✔
846
    }
847

848
    public static String formatJson(String json) {
849
        return formatJson(json, JsonStringBuilder.Step.TWO_SPACES);
1✔
850
    }
851
}
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