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

nats-io / nats.java / #2096

07 Aug 2025 08:19PM UTC coverage: 95.433% (-0.07%) from 95.507%
#2096

push

github

web-flow
Merge pull request #1382 from nats-io/json-parser-thanks-claude

Json parser tuning.

68 of 79 new or added lines in 1 file covered. (86.08%)

2 existing lines in 1 file now uncovered.

11868 of 12436 relevant lines covered (95.43%)

0.95 hits per line

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

94.55
/src/main/java/io/nats/client/support/JsonParser.java
1
// Copyright 2023 The NATS Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at:
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
package io.nats.client.support;
15

16
import org.jspecify.annotations.NonNull;
17
import org.jspecify.annotations.Nullable;
18

19
import java.math.BigDecimal;
20
import java.math.BigInteger;
21
import java.nio.ByteBuffer;
22
import java.nio.charset.CharacterCodingException;
23
import java.nio.charset.StandardCharsets;
24
import java.util.ArrayList;
25
import java.util.HashMap;
26
import java.util.List;
27
import java.util.Map;
28

29
/**
30
 * Class that can parse JSON to a JsonValue
31
 */
32
public class JsonParser {
33

34
    /**
35
     * Option for parsing.
36
     */
37
    public enum Option {
1✔
38
        /**
39
         * Keep nulls when parsing. Usually ignored
40
         */
41
        KEEP_NULLS
1✔
42
    }
43

44
    public static final String INVALID_VALUE = "Invalid value.";
45
    private static final boolean[] IS_DELIMITER = new boolean[128];
1✔
46

47
    static {
48
        for (char c : ",:]}/\\\"[{;=#".toCharArray()) {
1✔
49
            IS_DELIMITER[c] = true;
1✔
50
        }
51
    }
1✔
52

53
    private final StringBuilder workBuffer = new StringBuilder(64);
1✔
54

55
    /**
56
     * Parse JSON from a char array
57
     * @param json the JSON
58
     * @return the JsonValue
59
     * @throws JsonParseException if there is a problem parsing
60
     */
61
    @NonNull
62
    public static JsonValue parse(char @Nullable [] json) throws JsonParseException {
63
        return new JsonParser(json, 0).parse();
1✔
64
    }
65

66
    /**
67
     * Parse JSON from a char array, starting at the index
68
     * @param json the JSON
69
     * @param startIndex the starting index in the array
70
     * @return the JsonValue
71
     * @throws JsonParseException if there is a problem parsing
72
     */
73
    @NonNull
74
    public static JsonValue parse(char @Nullable [] json, int startIndex) throws JsonParseException {
75
        return new JsonParser(json, startIndex).parse();
1✔
76
    }
77

78
    /**
79
     * Parse JSON from a char array
80
     * @param json the JSON
81
     * @param options options for how to parse
82
     * @return the JsonValue
83
     * @throws JsonParseException if there is a problem parsing
84
     */
85
    @NonNull
86
    public static JsonValue parse(char @Nullable [] json, @Nullable Option... options) throws JsonParseException {
87
        return new JsonParser(json, 0, options).parse();
1✔
88
    }
89

90
    /**
91
     * Parse JSON from a char array
92
     * @param json the JSON
93
     * @param startIndex the starting index in the array
94
     * @param options options for how to parse
95
     * @return the JsonValue
96
     * @throws JsonParseException if there is a problem parsing
97
     */
98
    @NonNull
99
    public static JsonValue parse(char @Nullable [] json, int startIndex, @Nullable Option... options) throws JsonParseException {
100
        return new JsonParser(json, startIndex, options).parse();
1✔
101
    }
102

103

104
    /**
105
     * Parse JSON from a String
106
     * @param json the JSON
107
     * @return the JsonValue
108
     * @throws JsonParseException if there is a problem parsing
109
     */
110
    @NonNull
111
    public static JsonValue parse(String json) throws JsonParseException {
112
        return new JsonParser(json.toCharArray(), 0).parse();
1✔
113
    }
114

115

116
    /**
117
     * Parse JSON from a String
118
     * @param json the JSON
119
     * @param startIndex the starting index in the string
120
     * @return the JsonValue
121
     * @throws JsonParseException if there is a problem parsing
122
     */
123
    @NonNull
124
    public static JsonValue parse(String json, int startIndex) throws JsonParseException {
125
        return new JsonParser(json.toCharArray(), startIndex).parse();
1✔
126
    }
127

128
    /**
129
     * Parse JSON from a String
130
     * @param json the JSON
131
     * @param options options for how to parse
132
     * @return the JsonValue
133
     * @throws JsonParseException if there is a problem parsing
134
     */
135
    @NonNull
136
    public static JsonValue parse(String json, @Nullable Option... options) throws JsonParseException {
137
        return new JsonParser(json.toCharArray(), 0, options).parse();
1✔
138
    }
139

140
    /**
141
     * Parse JSON from a String
142
     * @param json the JSON
143
     * @param startIndex the starting index in the array
144
     * @param options options for how to parse
145
     * @return the JsonValue
146
     * @throws JsonParseException if there is a problem parsing
147
     */
148
    @NonNull
149
    public static JsonValue parse(String json, int startIndex, @Nullable Option... options) throws JsonParseException {
150
        return new JsonParser(json.toCharArray(), startIndex, options).parse();
1✔
151
    }
152

153
    /**
154
     * Parse JSON from a byte array
155
     * @param json the JSON
156
     * @return the JsonValue
157
     * @throws JsonParseException if there is a problem parsing
158
     */
159
    @NonNull
160
    public static JsonValue parse(byte[] json) throws JsonParseException {
161
        return new JsonParser(bytesToChars(json), 0).parse();
1✔
162
    }
163

164
    /**
165
     * Parse JSON from a byte array
166
     * @param json the JSON
167
     * @param startIndex the starting index in the array
168
     * @return the JsonValue
169
     * @throws JsonParseException if there is a problem parsing
170
     */
171
    @NonNull
172
    public static JsonValue parse(byte[] json, int startIndex) throws JsonParseException {
NEW
173
        return new JsonParser(bytesToChars(json), startIndex).parse();
×
174
    }
175

176
    /**
177
     * Parse JSON from a byte array
178
     * @param json the JSON
179
     * @param options options for how to parse
180
     * @return the JsonValue
181
     * @throws JsonParseException if there is a problem parsing
182
     */
183
    @NonNull
184
    public static JsonValue parse(byte[] json, @Nullable Option... options) throws JsonParseException {
185
        return new JsonParser(bytesToChars(json), 0, options).parse();
1✔
186
    }
187

188
    /**
189
     * Parse JSON from a byte array
190
     * @param json the JSON
191
     * @param startIndex the starting index in the array
192
     * @param options options for how to parse
193
     * @return the JsonValue
194
     * @throws JsonParseException if there is a problem parsing
195
     */
196
    @NonNull
197
    public static JsonValue parse(byte[] json, int startIndex, @Nullable Option... options) throws JsonParseException {
NEW
198
        return new JsonParser(bytesToChars(json), startIndex, options).parse();
×
199
    }
200

201
    /**
202
     * Parse JSON from a char array
203
     * @param json the JSON
204
     * @return the JsonValue
205
     * @throws RuntimeException if there is a problem parsing
206
     */
207
    @NonNull
208
    public static JsonValue parseUnchecked(char @Nullable [] json) {
209
        try { return parse(json); }
1✔
210
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
211
    }
212

213
    /**
214
     * Parse JSON from a char array
215
     * @param json the JSON
216
     * @param startIndex the starting index in the array
217
     * @return the JsonValue
218
     * @throws RuntimeException if there is a problem parsing
219
     */
220
    @NonNull
221
    public static JsonValue parseUnchecked(char @Nullable [] json, int startIndex) {
222
        try { return parse(json, startIndex); }
1✔
223
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
224
    }
225

226
    /**
227
     * Parse JSON from a char array
228
     * @param json the JSON
229
     * @param options options for how to parse
230
     * @return the JsonValue
231
     * @throws RuntimeException if there is a problem parsing
232
     */
233
    @NonNull
234
    public static JsonValue parseUnchecked(char @Nullable [] json, @Nullable Option... options) {
235
        try { return parse(json, options); }
1✔
236
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
237
    }
238

239
    /**
240
     * Parse JSON from a char array
241
     * @param json the JSON
242
     * @param startIndex the starting index in the array
243
     * @param options options for how to parse
244
     * @return the JsonValue
245
     * @throws RuntimeException if there is a problem parsing
246
     */
247
    @NonNull
248
    public static JsonValue parseUnchecked(char @Nullable [] json, int startIndex, @Nullable Option... options) {
249
        try { return parse(json, startIndex, options); }
1✔
250
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
251
    }
252

253
    /**
254
     * Parse JSON from a String
255
     * @param json the JSON
256
     * @return the JsonValue
257
     * @throws RuntimeException if there is a problem parsing
258
     */
259
    @NonNull
260
    public static JsonValue parseUnchecked(String json) {
261
        try { return parse(json); }
1✔
262
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
263
    }
264

265
    /**
266
     * Parse JSON from a String
267
     * @param json the JSON
268
     * @param startIndex the starting index in the string
269
     * @return the JsonValue
270
     * @throws RuntimeException if there is a problem parsing
271
     */
272
    @NonNull
273
    public static JsonValue parseUnchecked(String json, int startIndex) {
274
        try { return parse(json, startIndex); }
1✔
275
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
276
    }
277

278
    /**
279
     * Parse JSON from a String
280
     * @param json the JSON
281
     * @param options options for how to parse
282
     * @return the JsonValue
283
     * @throws RuntimeException if there is a problem parsing
284
     */
285
    @NonNull
286
    public static JsonValue parseUnchecked(String json, @Nullable Option... options) {
287
        try { return parse(json, options); }
1✔
288
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
289
    }
290

291
    /**
292
     * Parse JSON from a String
293
     * @param json the JSON
294
     * @param startIndex the starting index in the string
295
     * @param options options for how to parse
296
     * @return the JsonValue
297
     * @throws RuntimeException if there is a problem parsing
298
     */
299
    @NonNull
300
    public static JsonValue parseUnchecked(String json, int startIndex, @Nullable Option... options) {
301
        try { return parse(json, startIndex, options); }
1✔
302
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
303
    }
304

305
    /**
306
     * Parse JSON from a byte array
307
     * @param json the JSON
308
     * @return the JsonValue
309
     * @throws RuntimeException if there is a problem parsing
310
     */
311
    @NonNull
312
    public static JsonValue parseUnchecked(byte[] json) {
313
        try { return parse(json); }
1✔
314
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
315
    }
316

317
    /**
318
     * Parse JSON from a byte array
319
     * @param json the JSON
320
     * @param startIndex the starting index in the array
321
     * @return the JsonValue
322
     * @throws RuntimeException if there is a problem parsing
323
     */
324
    @NonNull
325
    public static JsonValue parseUnchecked(byte[] json, int startIndex) {
NEW
326
        try { return parse(json, startIndex); }
×
NEW
327
        catch (JsonParseException j) { throw new RuntimeException(j); }
×
328
    }
329

330
    /**
331
     * Parse JSON from a byte array
332
     * @param json the JSON
333
     * @param options options for how to parse
334
     * @return the JsonValue
335
     * @throws RuntimeException if there is a problem parsing
336
     */
337
    @NonNull
338
    public static JsonValue parseUnchecked(byte[] json, @Nullable Option... options) {
339
        try { return parse(json, options); }
1✔
340
        catch (JsonParseException j) { throw new RuntimeException(j); }
1✔
341
    }
342

343
    /**
344
     * Parse JSON from a byte array
345
     * @param json the JSON
346
     * @param startIndex the starting index in the array
347
     * @param options options for how to parse
348
     * @return the JsonValue
349
     * @throws RuntimeException if there is a problem parsing
350
     */
351
    @NonNull
352
    public static JsonValue parseUnchecked(byte[] json, int startIndex, @Nullable Option... options) {
NEW
353
        try { return parse(json, startIndex, options); }
×
NEW
354
        catch (JsonParseException j) { throw new RuntimeException(j); }
×
355
    }
356

357
    private final char @NonNull [] json;
358
    private final boolean keepNulls;
359
    private final int len;
360
    private int idx;
361
    private int nextIdx;
362
    private char previous;
363
    private char current;
364
    private char next;
365

366
    /**
367
     * Create a new JsonParse object from a char array
368
     * @param json the JSON
369
     */
370
    public JsonParser(char @Nullable [] json) {
371
        this(json, 0);
1✔
372
    }
1✔
373

374
    /**
375
     * Create a new JsonParse object from a char array
376
     * @param json the JSON
377
     * @param options options for how to parse
378
     */
379
    public JsonParser(char @Nullable [] json, @Nullable Option... options) {
380
        this(json, 0, options);
1✔
381
    }
1✔
382

383
    /**
384
     * Create a new JsonParse object from a char array
385
     * @param json the JSON
386
     * @param startIndex the starting index in the array
387
     * @param options options for how to parse
388
     */
389
    public JsonParser(char @Nullable [] json, int startIndex, @Nullable Option... options) {
1✔
390
        keepNulls = options != null && options.length > 0; // KEEP_NULLS is currently the only option
1✔
391

392
        if (json == null) {
1✔
393
            this.json = new char[0];
1✔
394
            len = 0;
1✔
395
        }
396
        else {
397
            this.json = json;
1✔
398
            len = json.length;
1✔
399
        }
400

401
        idx = startIndex;
1✔
402
        if (startIndex < 0) {
1✔
403
            throw new IllegalArgumentException("Invalid start index.");
1✔
404
        }
405
        nextIdx = -1;
1✔
406
        previous = 0;
1✔
407
        current = 0;
1✔
408
        next = 0;
1✔
409
    }
1✔
410

411
    /**
412
     * Parse the JSON
413
     * @return a JsonValue
414
     * @throws JsonParseException if there is a problem parsing
415
     */
416
    @NonNull
417
    public JsonValue parse() throws JsonParseException {
418
        char c = peekToken();
1✔
419
        if (c == 0) {
1✔
420
            return JsonValue.NULL;
1✔
421
        }
422
        return nextValue();
1✔
423
    }
424

425
    private JsonValue nextValue() throws JsonParseException {
426
        char c = peekToken();
1✔
427
        if (c == 0) {
1✔
428
            throw new JsonParseException("Unexpected end of data.");
1✔
429
        }
430
        if (c == '"') {
1✔
431
            nextToken();
1✔
432
            return new JsonValue(nextString());
1✔
433
        }
434
        if (c == '{') {
1✔
435
            nextToken();
1✔
436
            return new JsonValue(nextObject());
1✔
437
        }
438
        if (c == '[') {
1✔
439
            nextToken();
1✔
440
            return new JsonValue(nextArray());
1✔
441
        }
442
        return nextPrimitiveValue();
1✔
443
    }
444

445
    private List<JsonValue> nextArray() throws JsonParseException {
446
        List<JsonValue> list = new ArrayList<>(8);
1✔
447
        char p = peekToken();
1✔
448
        while (p != ']') {
1✔
449
            if (p == ',') {
1✔
450
                nextToken(); // advance past the peek
1✔
451
            }
452
            else {
453
                list.add(nextValue());
1✔
454
            }
455
            p = peekToken();
1✔
456
        }
457
        nextToken(); // advance past the peek
1✔
458
        return list;
1✔
459
    }
460

461
    private JsonValue nextPrimitiveValue() throws JsonParseException {
462
        workBuffer.setLength(0);
1✔
463
        char c = peekToken();
1✔
464
        while (c >= ' ' && isNotDelimiter(c)) {
1✔
465
            workBuffer.append(nextToken());
1✔
466
            c = peekToken();
1✔
467
        }
468
        String string = workBuffer.toString();
1✔
469
        if (string.length() == 4) {
1✔
470
            if ("true".equals(string)) {
1✔
471
                return JsonValue.TRUE;
1✔
472
            }
473
            if ("null".equals(string)) {
1✔
474
                return JsonValue.NULL;
1✔
475
            }
476
        }
477
        else if (string.length() == 5) {
1✔
478
            if ("false".equals(string)) {
1✔
479
                return JsonValue.FALSE;
1✔
480
            }
481
        }
482
        return asNumber(string);
1✔
483
    }
484

485
    // next object assumes you have already seen the starting {
486
    private Map<String, JsonValue> nextObject() throws JsonParseException {
487
        Map<String, JsonValue> map = new HashMap<>(8);
1✔
488
        String key;
489
        while (true) {
490
            char c = nextToken();
1✔
491
            switch (c) {
1✔
492
                case 0:
493
                    throw new JsonParseException("Text must end with '}'");
1✔
494
                case '}':
495
                    return map;
1✔
496
                case '{':
497
                case '[':
498
                    if (previous == '{') {
1✔
499
                        throw new JsonParseException("Cannot directly nest another Object or Array.");
1✔
500
                    }
501
                    // fall through
502
                default:
503
                    key = nextString();
1✔
504
            }
505

506
            c = nextToken();
1✔
507
            if (c != ':') {
1✔
508
                throw new JsonParseException("Expected a ':' after a key.");
1✔
509
            }
510

511
            JsonValue value = nextValue();
1✔
512
            if (value != JsonValue.NULL || keepNulls) {
1✔
513
                map.put(key, value);
1✔
514
            }
515

516
            switch (nextToken()) {
1✔
517
                case ',':
518
                    if (peekToken() == '}') {
1✔
519
                        return map; // dangling comma
1✔
520
                    }
521
                    break;
522
                case '}':
523
                    return map;
1✔
524
                default:
525
                    throw new JsonParseException("Expected a ',' or '}'.");
1✔
526
            }
527
        }
1✔
528
    }
529

530
    private char nextToken() {
531
        peekToken();
1✔
532
        idx = nextIdx;
1✔
533
        nextIdx = -1;
1✔
534
        previous = current;
1✔
535
        current = next;
1✔
536
        next = 0;
1✔
537
        return current;
1✔
538
    }
539

540
    private char nextChar() {
541
        previous = current;
1✔
542
        if (idx == len) {
1✔
543
            current = 0;
1✔
544
        }
545
        else {
546
            current = json[idx++];
1✔
547
        }
548
        next = 0;
1✔
549
        nextIdx = -1;
1✔
550
        return current;
1✔
551
    }
552

553
    private char peekToken() {
554
        if (nextIdx == -1) {
1✔
555
            nextIdx = idx;
1✔
556
            next = 0;
1✔
557
            while (nextIdx < len) {
1✔
558
                char c = json[nextIdx++];
1✔
559
                switch (c) {
1✔
560
                    case ' ':
561
                    case '\r':
562
                    case '\n':
563
                    case '\t':
564
                        continue;
1✔
565
                }
566
                return next = c;
1✔
567
            }
568
        }
569
        return next;
1✔
570
    }
571

572
    // nextString() assumes you have already seen the starting quote
573
    private String nextString() throws JsonParseException {
574
        workBuffer.setLength(0);
1✔
575
        while (true) {
576
            char c = nextChar();
1✔
577
            switch (c) {
1✔
578
                case 0:
579
                case '\n':
580
                case '\r':
581
                    throw new JsonParseException("Unterminated string.");
1✔
582
                case '\\':
583
                    c = nextChar();
1✔
584
                    switch (c) {
1✔
585
                        case 'b':
586
                            workBuffer.append('\b');
1✔
587
                            break;
1✔
588
                        case 't':
589
                            workBuffer.append('\t');
1✔
590
                            break;
1✔
591
                        case 'n':
592
                            workBuffer.append('\n');
1✔
593
                            break;
1✔
594
                        case 'f':
595
                            workBuffer.append('\f');
1✔
596
                            break;
1✔
597
                        case 'r':
598
                            workBuffer.append('\r');
1✔
599
                            break;
1✔
600
                        case 'u':
601
                            workBuffer.append(parseU());
1✔
602
                            break;
1✔
603
                        case '"':
604
                        case '\'':
605
                        case '\\':
606
                        case '/':
607
                            workBuffer.append(c);
1✔
608
                            break;
1✔
609
                        default:
610
                            throw new JsonParseException("Illegal escape.");
1✔
611
                    }
612
                    break;
613
                default:
614
                    if (c == '"') {
1✔
615
                        return workBuffer.toString();
1✔
616
                    }
617
                    workBuffer.append(c);
1✔
618
            }
619
        }
1✔
620
    }
621

622
    private char[] parseU() throws JsonParseException {
623
        int code = 0;
1✔
624
        for (int i = 0; i < 4; i++) {
1✔
625
            char c = nextToken();
1✔
626
            if (c == 0) throw new JsonParseException("Illegal escape.");
1✔
627

628
            int digit;
629
            if (c >= '0' && c <= '9') digit = c - '0';
1✔
630
            else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
1✔
631
            else if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
1✔
632
            else throw new JsonParseException("Illegal escape.");
1✔
633

634
            code = (code << 4) | digit;
1✔
635
        }
636
        return Character.toChars(code);
1✔
637
    }
638

639
    private JsonValue asNumber(String val) throws JsonParseException {
640
        char initial = val.charAt(0);
1✔
641
        if ((initial >= '0' && initial <= '9') || initial == '-') {
1✔
642

643
            if (isDecimalNotation(val)) {
1✔
644
                // Use a BigDecimal all the time to keep the original
645
                // representation. BigDecimal doesn't support -0.0, ensure we
646
                // keep that by forcing a decimal.
647
                try {
648
                    BigDecimal bd = new BigDecimal(val);
1✔
649
                    if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
1✔
650
                        return new JsonValue(-0.0);
1✔
651
                    }
652
                    return new JsonValue(bd);
1✔
653
                } catch (NumberFormatException retryAsDouble) {
1✔
654
                    // this is to support "Hex Floats" like this: 0x1.0P-1074
655
                    try {
656
                        double d = Double.parseDouble(val);
1✔
657
                        if(Double.isNaN(d) || Double.isInfinite(d)) {
1✔
NEW
658
                            throw new JsonParseException(INVALID_VALUE);
×
659
                        }
660
                        return new JsonValue(d);
1✔
661
                    } catch (NumberFormatException ignore) {
×
NEW
662
                        throw new JsonParseException(INVALID_VALUE);
×
663
                    }
664
                }
665
            }
666

667
            // block items like 00 01 etc. Java number parsers treat these as Octal.
668
            if (initial == '0' && val.length() > 1) {
1✔
669
                char at1 = val.charAt(1);
1✔
670
                if(at1 >= '0' && at1 <= '9') {
1✔
671
                    throw new JsonParseException(INVALID_VALUE);
1✔
672
                }
673
            } else if (initial == '-' && val.length() > 2) {
1✔
674
                char at1 = val.charAt(1);
1✔
675
                char at2 = val.charAt(2);
1✔
676
                if (at1 == '0' && at2 >= '0' && at2 <= '9') {
1✔
NEW
677
                    throw new JsonParseException(INVALID_VALUE);
×
678
                }
679
            }
680

681
            // Try parsing as long first
682
            try {
683
                long longVal = Long.parseLong(val);
1✔
684
                if (longVal >= Integer.MIN_VALUE && longVal <= Integer.MAX_VALUE) {
1✔
685
                    return new JsonValue((int) longVal);
1✔
686
                }
687
                return new JsonValue(longVal);
1✔
688
            } catch (NumberFormatException e) {
1✔
689
                // Fall back to BigInteger for very large integers
690
                try {
691
                    BigInteger bi = new BigInteger(val);
1✔
692
                    return new JsonValue(bi);
1✔
693
                } catch (NumberFormatException ex) {
1✔
694
                    throw new JsonParseException(INVALID_VALUE);
1✔
695
                }
696
            }
697
        }
698
        throw new JsonParseException(INVALID_VALUE);
1✔
699
    }
700

701
    static boolean isDecimalNotation(final String val) {
702
        return val.indexOf('.') > -1 || val.indexOf('e') > -1
1✔
703
            || val.indexOf('E') > -1 || "-0".equals(val);
1✔
704
    }
705

706
    private boolean isNotDelimiter(char c) {
707
        return c < 128 && !IS_DELIMITER[c];
1✔
708
    }
709

710
    private static char[] bytesToChars(byte[] json) throws JsonParseException {
711
        try {
712
            return StandardCharsets.UTF_8.newDecoder().decode(ByteBuffer.wrap(json)).array();
1✔
713
        }
NEW
714
        catch (CharacterCodingException e) {
×
NEW
715
            throw new JsonParseException(e);
×
716
        }
717
    }
718
}
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

© 2026 Coveralls, Inc