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

nats-io / nats.java / #1870

17 Feb 2025 01:09PM UTC coverage: 95.711% (+0.009%) from 95.702%
#1870

push

github

web-flow
feature: update_service_to_support_adding_endpoint_after_construction (#1274)

* update_service_to_support_adding_dynamic_endpoint_after_service_construction

* revert format change & restrict empty list to InfoResponse

* revert format change & restrict empty list to InfoResponse

* revert format change & restrict empty list to InfoResponse

* revert format change & restrict empty list to InfoResponse

* adding comments for 2 discovery contexts

* sync with infoResponsse, adding empty list

38 of 44 new or added lines in 5 files covered. (86.36%)

1 existing line in 1 file now uncovered.

11447 of 11960 relevant lines covered (95.71%)

0.96 hits per line

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

97.53
/src/main/java/io/nats/client/support/JsonUtils.java
1
// Copyright 2020 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 io.nats.client.impl.Headers;
17

18
import java.nio.charset.StandardCharsets;
19
import java.time.Duration;
20
import java.time.ZonedDateTime;
21
import java.util.*;
22
import java.util.function.Consumer;
23
import java.util.function.IntConsumer;
24
import java.util.function.LongConsumer;
25
import java.util.regex.Matcher;
26
import java.util.regex.Pattern;
27

28
import static io.nats.client.support.DateTimeUtils.DEFAULT_TIME;
29
import static io.nats.client.support.Encoding.jsonDecode;
30
import static io.nats.client.support.Encoding.jsonEncode;
31
import static io.nats.client.support.JsonValueUtils.instance;
32
import static io.nats.client.support.NatsConstants.COLON;
33

34
/**
35
 * Internal json parsing helpers.
36
 * Read helpers deprecated Prefer using the {@link JsonParser}
37
 */
38
public abstract class JsonUtils {
39
    public static final String EMPTY_JSON = "{}";
40

41
    private static final String STRING_RE  = "\"(.+?)\"";
42
    private static final String BOOLEAN_RE =  "(true|false)";
43
    private static final String INTEGER_RE =  "(-?\\d+)";
44
    private static final String STRING_ARRAY_RE = "\\[\\s*(\".+?\")\\s*\\]";
45
    private static final String NUMBER_ARRAY_RE = "\\[\\s*(.+?)\\s*\\]";
46
    private static final String BEFORE_FIELD_RE = "\"";
47
    private static final String AFTER_FIELD_RE = "\"\\s*:\\s*";
48

49
    private static final String Q = "\"";
50
    private static final String QCOLONQ = "\":\"";
51
    private static final String QCOLON = "\":";
52
    private static final String QCOMMA = "\",";
53
    private static final String COMMA = ",";
54
    public static final String OPENQ = "{\"";
55
    public static final String CLOSE = "}";
56

57
    private JsonUtils() {} /* ensures cannot be constructed */
58

59
    // ----------------------------------------------------------------------------------------------------
60
    // BUILD A STRING OF JSON
61
    // ----------------------------------------------------------------------------------------------------
62
    public static StringBuilder beginJson() {
63
        return new StringBuilder("{");
1✔
64
    }
65

66
    public static StringBuilder beginArray() {
67
        return new StringBuilder("[");
1✔
68
    }
69

70
    public static StringBuilder beginJsonPrefixed(String prefix) {
71
        return prefix == null ? beginJson()
1✔
72
            : new StringBuilder(prefix).append('{');
1✔
73
    }
74

75
    public static StringBuilder endJson(StringBuilder sb) {
76
        int lastIndex = sb.length() - 1;
1✔
77
        if (sb.charAt(lastIndex) == ',') {
1✔
78
            sb.setCharAt(lastIndex, '}');
1✔
79
            return sb;
1✔
80
        }
81
        sb.append("}");
1✔
82
        return sb;
1✔
83
    }
84

85
    public static StringBuilder endArray(StringBuilder sb) {
86
        int lastIndex = sb.length() - 1;
1✔
87
        if (sb.charAt(lastIndex) == ',') {
1✔
88
            sb.setCharAt(lastIndex, ']');
1✔
89
            return sb;
1✔
90
        }
91
        sb.append("]");
1✔
92
        return sb;
1✔
93
    }
94

95
    public static StringBuilder beginFormattedJson() {
96
        return new StringBuilder("{\n    ");
1✔
97
    }
98

99
    public static String endFormattedJson(StringBuilder sb) {
100
        sb.setLength(sb.length()-1);
1✔
101
        sb.append("\n}");
1✔
102
        return sb.toString().replaceAll(",", ",\n    ");
1✔
103
    }
104

105
    /**
106
     * Appends a json field to a string builder.
107
     * @param sb string builder
108
     * @param fname fieldname
109
     * @param json raw json
110
     */
111
    public static void addRawJson(StringBuilder sb, String fname, String json) {
112
        if (json != null && json.length() > 0) {
1✔
113
            sb.append(Q);
1✔
114
            jsonEncode(sb, fname);
1✔
115
            sb.append(QCOLON);
1✔
116
            sb.append(json);
1✔
117
            sb.append(COMMA);
1✔
118
        }
119
    }
1✔
120

121
    /**
122
     * Appends a json field to a string builder.
123
     * @param sb string builder
124
     * @param fname fieldname
125
     * @param value field value
126
     */
127
    public static void addField(StringBuilder sb, String fname, String value) {
128
        if (value != null && value.length() > 0) {
1✔
129
            sb.append(Q);
1✔
130
            jsonEncode(sb, fname);
1✔
131
            sb.append(QCOLONQ);
1✔
132
            jsonEncode(sb, value);
1✔
133
            sb.append(QCOMMA);
1✔
134
        }
135
    }
1✔
136

137
    /**
138
     * Appends a json field to a string builder. Empty and null string are added as value of empty string
139
     * @param sb string builder
140
     * @param fname fieldname
141
     * @param value field value
142
     */
143
    public static void addFieldEvenEmpty(StringBuilder sb, String fname, String value) {
144
        if (value == null) {
1✔
145
            value = "";
1✔
146
        }
147
        sb.append(Q);
1✔
148
        jsonEncode(sb, fname);
1✔
149
        sb.append(QCOLONQ);
1✔
150
        jsonEncode(sb, value);
1✔
151
        sb.append(QCOMMA);
1✔
152
    }
1✔
153

154
    /**
155
     * Appends a json field to a string builder.
156
     * @param sb string builder
157
     * @param fname fieldname
158
     * @param value field value
159
     */
160
    public static void addField(StringBuilder sb, String fname, Boolean value) {
161
        if (value != null) {
1✔
162
            sb.append(Q);
1✔
163
            jsonEncode(sb, fname);
1✔
164
            sb.append(QCOLON).append(value ? "true" : "false").append(COMMA);
1✔
165
        }
166
    }
1✔
167

168
    /**
169
     * Appends a json field to a string builder.
170
     * @param sb string builder
171
     * @param fname fieldname
172
     * @param value field value
173
     */
174
    public static void addFldWhenTrue(StringBuilder sb, String fname, Boolean value) {
175
        if (value != null && value) {
1✔
176
            addField(sb, fname, true);
1✔
177
        }
178
    }
1✔
179

180
    /**
181
     * Appends a json field to a string builder.
182
     * @param sb string builder
183
     * @param fname fieldname
184
     * @param value field value
185
     */
186
    public static void addField(StringBuilder sb, String fname, Integer value) {
187
        if (value != null && value >= 0) {
1✔
188
            sb.append(Q);
1✔
189
            jsonEncode(sb, fname);
1✔
190
            sb.append(QCOLON).append(value).append(COMMA);
1✔
191
        }
192
    }
1✔
193

194
    /**
195
     * Appends a json field to a string builder.
196
     * @param sb string builder
197
     * @param fname fieldname
198
     * @param value field value
199
     */
200
    public static void addFieldWhenGtZero(StringBuilder sb, String fname, Integer value) {
201
        if (value != null && value > 0) {
1✔
202
            sb.append(Q);
1✔
203
            jsonEncode(sb, fname);
1✔
204
            sb.append(QCOLON).append(value).append(COMMA);
1✔
205
        }
206
    }
1✔
207

208
    /**
209
     * Appends a json field to a string builder.
210
     * @param sb string builder
211
     * @param fname fieldname
212
     * @param value field value
213
     */
214
    public static void addField(StringBuilder sb, String fname, Long value) {
215
        if (value != null && value >= 0) {
1✔
216
            sb.append(Q);
1✔
217
            jsonEncode(sb, fname);
1✔
218
            sb.append(QCOLON).append(value).append(COMMA);
1✔
219
        }
220
    }
1✔
221

222
    /**
223
     * Appends a json field to a string builder.
224
     * @param sb string builder
225
     * @param fname fieldname
226
     * @param value field value
227
     */
228
    public static void addFieldWhenGtZero(StringBuilder sb, String fname, Long value) {
229
        if (value != null && value > 0) {
1✔
230
            sb.append(Q);
1✔
231
            jsonEncode(sb, fname);
1✔
232
            sb.append(QCOLON).append(value).append(COMMA);
1✔
233
        }
234
    }
1✔
235

236
    /**
237
     * Appends a json field to a string builder.
238
     * @param sb string builder
239
     * @param fname fieldname
240
     * @param value field value
241
     */
242
    public static void addFieldWhenGteMinusOne(StringBuilder sb, String fname, Long value) {
243
        if (value != null && value >= -1) {
1✔
244
            sb.append(Q);
1✔
245
            jsonEncode(sb, fname);
1✔
246
            sb.append(QCOLON).append(value).append(COMMA);
1✔
247
        }
248
    }
1✔
249

250
    /**
251
     * Appends a json field to a string builder.
252
     * @param sb string builder
253
     * @param fname fieldname
254
     * @param value field value
255
     * @param gt the number the value must be greater than
256
     */
257
    public static void addFieldWhenGreaterThan(StringBuilder sb, String fname, Long value, long gt) {
258
        if (value != null && value > gt) {
1✔
259
            sb.append(Q);
1✔
260
            jsonEncode(sb, fname);
1✔
261
            sb.append(QCOLON).append(value).append(COMMA);
1✔
262
        }
263
    }
1✔
264

265
    /**
266
     * Appends a json field to a string builder.
267
     * @param sb string builder
268
     * @param fname fieldname
269
     * @param value duration value
270
     */
271
    public static void addFieldAsNanos(StringBuilder sb, String fname, Duration value) {
272
        if (value != null && !value.isZero() && !value.isNegative()) {
1✔
273
            sb.append(Q);
1✔
274
            jsonEncode(sb, fname);
1✔
275
            sb.append(QCOLON).append(value.toNanos()).append(COMMA);
1✔
276
        }
277
    }
1✔
278

279
    /**
280
     * Appends a json object to a string builder.
281
     * @param sb string builder
282
     * @param fname fieldname
283
     * @param value JsonSerializable value
284
     */
285
    public static void addField(StringBuilder sb, String fname, JsonSerializable value) {
286
        if (value != null) {
1✔
287
            sb.append(Q);
1✔
288
            jsonEncode(sb, fname);
1✔
289
            sb.append(QCOLON).append(value.toJson()).append(COMMA);
1✔
290
        }
291
    }
1✔
292

293
    public static void addField(StringBuilder sb, String fname, Map<String, String> map) {
294
        if (map != null && map.size() > 0) {
1✔
295
            addField(sb, fname, instance(map));
1✔
296
        }
297
    }
1✔
298

299
    @SuppressWarnings("rawtypes")
300
    public static void addEnumWhenNot(StringBuilder sb, String fname, Enum e, Enum dontAddIfThis) {
301
        if (e != null && e != dontAddIfThis) {
1✔
302
            addField(sb, fname, e.toString());
1✔
303
        }
304
    }
1✔
305

306
    public interface ListAdder<T> {
307
        void append(StringBuilder sb, T t);
308
    }
309

310
    /**
311
     * Appends a json field to a string builder.
312
     * @param <T> the list type
313
     * @param sb string builder
314
     * @param fname fieldname
315
     * @param list value list
316
     * @param adder implementation to add value, including its quotes if required
317
     */
318
    public static <T> void _addList(StringBuilder sb, String fname, List<T> list, ListAdder<T> adder) {
319
        sb.append(Q);
1✔
320
        jsonEncode(sb, fname);
1✔
321
        sb.append("\":[");
1✔
322
        for (int i = 0; i < list.size(); i++) {
1✔
323
            if (i > 0) {
1✔
324
                sb.append(COMMA);
1✔
325
            }
326
            adder.append(sb, list.get(i));
1✔
327
        }
328
        sb.append("],");
1✔
329
    }
1✔
330

331
    /**
332
     * Appends an empty JSON array to a string builder with the specified field name.
333
     * @param sb the string builder to append to
334
     * @param fname the name of the JSON field
335
     */
336
    private static void _addEmptyList(StringBuilder sb, String fname) {
NEW
337
        sb.append(Q);
×
NEW
338
        jsonEncode(sb, fname);
×
NEW
339
        sb.append("\":[],");
×
NEW
340
    }
×
341

342
    /**
343
     * Appends a json field to a string builder.
344
     * @param sb string builder
345
     * @param fname fieldname
346
     * @param strings field value
347
     */
348
    public static void addStrings(StringBuilder sb, String fname, String[] strings) {
349
        if (strings != null && strings.length > 0) {
1✔
350
            _addStrings(sb, fname, Arrays.asList(strings));
1✔
351
        }
352
    }
1✔
353

354
    /**
355
     * Appends a json field to a string builder.
356
     * @param sb string builder
357
     * @param fname fieldname
358
     * @param strings field value
359
     */
360
    public static void addStrings(StringBuilder sb, String fname, List<String> strings) {
361
        if (strings != null && strings.size() > 0) {
1✔
362
            _addStrings(sb, fname, strings);
1✔
363
        }
364
    }
1✔
365

366
    private static void _addStrings(StringBuilder sb, String fname, List<String> strings) {
367
        _addList(sb, fname, strings, (sbs, s) -> {
1✔
368
            sb.append(Q);
1✔
369
            jsonEncode(sb, s);
1✔
370
            sb.append(Q);
1✔
371
        });
1✔
372
    }
1✔
373

374
    /**
375
     * Appends a json field to a string builder.
376
     * @param sb string builder
377
     * @param fname fieldname
378
     * @param jsons field value
379
     */
380
    public static void addJsons(StringBuilder sb, String fname, List<? extends JsonSerializable> jsons) {
381
        addJsons(sb, fname, jsons, false);
1✔
382
    }
1✔
383

384
    /**
385
     * Appends a json field to a string builder and the additional flag to indicate if an empty list to be added.
386
     * @param sb string builder
387
     * @param fname fieldname
388
     * @param jsons field value
389
     * @param addEmptyList flag to indicate if an empty list to be added
390
     */
391
    public static void addJsons(StringBuilder sb, String fname, List<? extends JsonSerializable> jsons, boolean addEmptyList) {
392
        if (jsons != null && !jsons.isEmpty()) {
1✔
393
            _addList(sb, fname, jsons, (sbs, s) -> sbs.append(s.toJson()));
1✔
394
        }
395
        else if (addEmptyList) {
1✔
NEW
396
            _addEmptyList(sb, fname);
×
397
        }
398
    }
1✔
399

400
    /**
401
     * Appends a json field to a string builder.
402
     * @param sb string builder
403
     * @param fname fieldname
404
     * @param durations list of durations
405
     */
406
    public static void addDurations(StringBuilder sb, String fname, List<Duration> durations) {
407
        if (durations != null && durations.size() > 0) {
1✔
408
            _addList(sb, fname, durations, (sbs, dur) -> sbs.append(dur.toNanos()));
1✔
409
        }
410
    }
1✔
411

412
    /**
413
     * Appends a date/time to a string builder as a rfc 3339 formatted field.
414
     * @param sb string builder
415
     * @param fname fieldname
416
     * @param zonedDateTime field value
417
     */
418
    public static void addField(StringBuilder sb, String fname, ZonedDateTime zonedDateTime) {
419
        if (zonedDateTime != null && !DEFAULT_TIME.equals(zonedDateTime)) {
1✔
420
            sb.append(Q);
1✔
421
            jsonEncode(sb, fname);
1✔
422
            sb.append(QCOLONQ)
1✔
423
                .append(DateTimeUtils.toRfc3339(zonedDateTime))
1✔
424
                .append(QCOMMA);
1✔
425
        }
426
    }
1✔
427

428
    public static void addField(StringBuilder sb, String fname, Headers headers) {
429
        if (headers != null && headers.size() > 0) {
1✔
430
            sb.append(Q);
1✔
431
            jsonEncode(sb, fname);
1✔
432
            sb.append("\":{");
1✔
433
            for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
1✔
434
                addStrings(sb, entry.getKey(), entry.getValue());
1✔
435
            }
1✔
436
            endJson(sb);
1✔
437
            sb.append(",");
1✔
438
        }
439
    }
1✔
440

441
    // ----------------------------------------------------------------------------------------------------
442
    // PRINT UTILS
443
    // ----------------------------------------------------------------------------------------------------
444
    @Deprecated
445
    public static String normalize(String s) {
446
        return Character.toString(s.charAt(0)).toUpperCase() + s.substring(1).toLowerCase();
1✔
447
    }
448

449
    public static String toKey(Class<?> c) {
450
        return "\"" + c.getSimpleName() + "\":";
1✔
451
    }
452

453
    @Deprecated
454
    public static String objectString(String name, Object o) {
455
        if (o == null) {
1✔
456
            return name + "=null";
1✔
457
        }
458
        return o.toString();
1✔
459
    }
460

461
    private static final String INDENT = "                                        ";
462
    private static String indent(int level) {
463
        return level == 0 ? "" : INDENT.substring(0, level * 4);
1✔
464
    }
465

466
    /**
467
     * This isn't perfect but good enough for debugging
468
     * @param o the object
469
     * @return the formatted string
470
     */
471
    public static String getFormatted(Object o) {
472
        StringBuilder sb = new StringBuilder();
1✔
473
        int level = 0;
1✔
474
        int arrayLevel = 0;
1✔
475
        boolean lastWasClose = false;
1✔
476
        boolean indentNext = true;
1✔
477
        String indent = "";
1✔
478
        String s = o.toString();
1✔
479
        for (int x = 0; x < s.length(); x++) {
1✔
480
            char c = s.charAt(x);
1✔
481
            if (c == '{') {
1✔
482
                if (arrayLevel > 0 && lastWasClose) {
1✔
483
                    sb.append(indent);
1✔
484
                }
485
                sb.append(c).append('\n');
1✔
486
                indent = indent(++level);
1✔
487
                indentNext = true;
1✔
488
                lastWasClose = false;
1✔
489
            }
490
            else if (c == '}') {
1✔
491
                indent = indent(--level);
1✔
492
                sb.append('\n').append(indent).append(c);
1✔
493
                lastWasClose = true;
1✔
494
            }
495
            else if (c == ',') {
1✔
496
                sb.append(",\n");
1✔
497
                indentNext = true;
1✔
498
            }
499
            else {
500
                if (c == '[') {
1✔
501
                    arrayLevel++;
1✔
502
                }
503
                else if (c == ']') {
1✔
504
                    arrayLevel--;
1✔
505
                }
506
                if (indentNext) {
1✔
507
                    if (c != ' ') {
1✔
508
                        sb.append(indent).append(c);
1✔
509
                        indentNext = false;
1✔
510
                    }
511
                }
512
                else {
513
                    sb.append(c);
1✔
514
                }
515
                lastWasClose = lastWasClose && Character.isWhitespace(c);
1✔
516
            }
517
        }
518
        return sb.toString();
1✔
519
    }
520

521
    public static void printFormatted(Object o) {
522
        System.out.println(getFormatted(o));
1✔
523
    }
1✔
524

525
    // ----------------------------------------------------------------------------------------------------
526
    // SAFE NUMBER PARSING HELPERS
527
    // ----------------------------------------------------------------------------------------------------
528
    public static Long safeParseLong(String s) {
529
        try {
530
            return Long.parseLong(s);
1✔
531
        }
532
        catch (Exception e1) {
1✔
533
            try {
534
                return Long.parseUnsignedLong(s);
1✔
535
            }
536
            catch (Exception e2) {
1✔
537
                return null;
1✔
538
            }
539
        }
540
    }
541

542
    public static long safeParseLong(String s, long dflt) {
543
        Long l = safeParseLong(s);
1✔
544
        return l == null ? dflt : l;
1✔
545
    }
546

547
    // ----------------------------------------------------------------------------------------------------
548
    // REGEX READING OF JSON. DEPRECATED PREFER USING THE JsonParser
549
    // ----------------------------------------------------------------------------------------------------
550
    @Deprecated
1✔
551
    public enum FieldType {
552
        jsonString(STRING_RE),
1✔
553
        jsonBoolean(BOOLEAN_RE),
1✔
554
        jsonInteger(INTEGER_RE),
1✔
555
        jsonNumber(INTEGER_RE),
1✔
556
        jsonStringArray(STRING_ARRAY_RE);
1✔
557

558
        final String re;
559
        FieldType(String re) {
1✔
560
            this.re = re;
1✔
561
        }
1✔
562
    }
563

564
    @Deprecated
565
    public static Pattern string_pattern(String field) {
566
        return buildPattern(field, STRING_RE);
1✔
567
    }
568

569
    @Deprecated
570
    public static Pattern number_pattern(String field) {
571
        return integer_pattern(field);
1✔
572
    }
573

574
    @Deprecated
575
    public static Pattern integer_pattern(String field) {
576
        return buildPattern(field, INTEGER_RE);
1✔
577
    }
578

579
    @Deprecated
580
    public static Pattern boolean_pattern(String field) {
581
        return buildPattern(field, BOOLEAN_RE);
1✔
582
    }
583

584
    @Deprecated
585
    public static Pattern string_array_pattern(String field) {
586
        return buildPattern(field, STRING_ARRAY_RE);
1✔
587
    }
588

589
    @Deprecated
590
    public static Pattern number_array_pattern(String field) {
591
        return buildPattern(field, NUMBER_ARRAY_RE);
1✔
592
    }
593

594
    /**
595
     * Builds a json parsing pattern
596
     * @param fieldName name of the field
597
     * @param type type of the field.
598
     * @return pattern.
599
     */
600
    @Deprecated
601
    public static Pattern buildPattern(String fieldName, FieldType type) {
602
        return buildPattern(fieldName, type.re);
1✔
603
    }
604

605
    @Deprecated
606
    public static Pattern buildPattern(String fieldName, String typeRE) {
607
        return Pattern.compile(BEFORE_FIELD_RE + fieldName + AFTER_FIELD_RE + typeRE, Pattern.CASE_INSENSITIVE);
1✔
608
    }
609

610
    /**
611
     * Extract a JSON object string by object name. Returns empty object '{}' if not found.
612
     * @param objectName object name
613
     * @param json source json
614
     * @return object json string
615
     */
616
    @Deprecated
617
    public static String getJsonObject(String objectName, String json) {
618
        return getJsonObject(objectName, json, EMPTY_JSON);
1✔
619
    }
620

621
    @Deprecated
622
    public static String getJsonObject(String objectName, String json, String dflt) {
623
        int[] indexes = getBracketIndexes(objectName, json, '{', '}', 0);
1✔
624
        return indexes == null ? dflt : json.substring(indexes[0], indexes[1] + 1);
1✔
625
    }
626

627
    @Deprecated
628
    public static String removeObject(String json, String objectName) {
629
        int[] indexes = getBracketIndexes(objectName, json, '{', '}', 0);
1✔
630
        if (indexes != null) {
1✔
631
            // remove the entire object replacing it with a dummy field b/c getBracketIndexes doesn't consider
632
            // if there is or isn't another object after it, so I don't have to worry about it being/not being the last object
633
            json = json.substring(0, indexes[0]) + "\"rmvd" + objectName.hashCode() + "\":\"\"" + json.substring(indexes[1] + 1);
×
634
        }
635
        return json;
1✔
636
    }
637

638
    /**
639
     * Extract a list JSON object strings for list object name. Returns empty list '{}' if not found.
640
     * Assumes that there are no brackets '{' or '}' in the actual data.
641
     * @param objectName list object name
642
     * @param json source json
643
     * @return object json string
644
     */
645
    @Deprecated
646
    public static List<String> getObjectList(String objectName, String json) {
647
        List<String> items = new ArrayList<>();
1✔
648
        int[] indexes = getBracketIndexes(objectName, json, '[', ']', -1);
1✔
649
        if (indexes != null) {
1✔
650
            StringBuilder item = new StringBuilder();
1✔
651
            int depth = 0;
1✔
652
            for (int x = indexes[0] + 1; x < indexes[1]; x++) {
1✔
653
                char c = json.charAt(x);
1✔
654
                if (c == '{') {
1✔
655
                    item.append(c);
1✔
656
                    depth++;
1✔
657
                } else if (c == '}') {
1✔
658
                    item.append(c);
1✔
659
                    if (--depth == 0) {
1✔
660
                        items.add(item.toString());
1✔
661
                        item.setLength(0);
1✔
662
                    }
663
                } else if (depth > 0) {
1✔
664
                    item.append(c);
1✔
665
                }
666
            }
667
        }
668
        return items;
1✔
669
    }
670

671
    private static int[] getBracketIndexes(String objectName, String json, char start, char end, int fromIndex) {
672
        int[] result = new int[] {-1, -1};
1✔
673
        int objStart = json.indexOf(Q + objectName + Q, fromIndex);
1✔
674
        if (objStart != -1) {
1✔
675
            int startIx;
676
            if (fromIndex != -1) {
1✔
677
                int colonMark = json.indexOf(COLON, objStart) + 1;
1✔
678
                startIx = json.indexOf(start, colonMark);
1✔
679
                for (int x = colonMark; x < startIx; x++) {
1✔
680
                    char c = json.charAt(x);
1✔
681
                    if (!Character.isWhitespace(c)) {
1✔
682
                        return getBracketIndexes(objectName, json, start, end, colonMark);
1✔
683
                    }
684
                }
685
            }
1✔
686
            else {
687
                startIx = json.indexOf(start, objStart);
1✔
688
            }
689
            int depth = 1;
1✔
690
            for (int x = startIx + 1; x < json.length(); x++) {
1✔
691
                char c = json.charAt(x);
1✔
692
                if (c == start) {
1✔
693
                    depth++;
1✔
694
                }
695
                else if (c == end) {
1✔
696
                    if (--depth == 0) {
1✔
697
                        result[0] = startIx;
1✔
698
                        result[1] = x;
1✔
699
                        return result;
1✔
700
                    }
701
                }
702
            }
703
        }
704
        return null;
1✔
705
    }
706

707
    /**
708
     * Get a map of objects
709
     * @param json the json
710
     * @return the map of json object strings by key
711
     */
712
    @Deprecated
713
    public static Map<String, String> getMapOfObjects(String json) {
714
        Map<String, String> map = new HashMap<>();
1✔
715
        int s1 = json.indexOf('"');
1✔
716
        while (s1 != -1) {
1✔
717
            int s2 = json.indexOf('"', s1 + 1);
1✔
718
            String key = json.substring(s1 + 1, s2).trim();
1✔
719
            int[] indexes = getBracketIndexes(key, json, '{', '}', s1);
1✔
720
            if (indexes != null) {
1✔
721
                map.put(key, json.substring(indexes[0], indexes[1] + 1));
×
722
                s1 = json.indexOf('"', indexes[1]);
×
723
            }
724
            else {
725
                s1 = -1;
1✔
726
            }
727
        }
1✔
728

729
        return map;
1✔
730
    }
731

732
    /**
733
     * Get a map of objects
734
     * @param json the json
735
     * @return the map of json object strings by key
736
     */
737
    @Deprecated
738
    public static Map<String, List<String>> getMapOfLists(String json) {
739
        Map<String, List<String>> map = new HashMap<>();
1✔
740
        int s1 = json.indexOf('"');
1✔
741
        while (s1 != -1) {
1✔
742
            int s2 = json.indexOf('"', s1 + 1);
1✔
743
            String key = json.substring(s1 + 1, s2).trim();
1✔
744
            int[] indexes = getBracketIndexes(key, json, '[', ']', s1);
1✔
745
            if (indexes != null) {
1✔
746
                map.put(key, toList(json.substring(indexes[0] + 1, indexes[1])));
×
747
                s1 = json.indexOf('"', indexes[1]);
×
748
            }
749
            else {
750
                s1 = -1;
1✔
751
            }
752
        }
1✔
753

754
        return map;
1✔
755
    }
756

757
    /**
758
     * Get a map of longs
759
     * @param json the json
760
     * @return the map of longs by key
761
     */
762
    @Deprecated
763
    public static Map<String, Long> getMapOfLongs(String json) {
764
        Map<String, Long> map = new HashMap<>();
1✔
765
        int s1 = json.indexOf('"');
1✔
766
        while (s1 != -1) {
1✔
767
            int s2 = json.indexOf('"', s1 + 1);
1✔
768
            int c1 = json.indexOf(':', s2);
1✔
769
            int c2 = json.indexOf(',', s2);
1✔
770
            if (c2 == -1) {
1✔
771
                c2 = json.indexOf('}', s2);
1✔
772
            }
773
            String key = json.substring(s1 + 1, s2).trim();
1✔
774
            long count = safeParseLong(json.substring(c1 + 1, c2).trim(), 0);
1✔
775
            map.put(key, count);
1✔
776
            s1 = json.indexOf('"', c2);
1✔
777
        }
1✔
778
        return map;
1✔
779
    }
780

781
    /**
782
     * Extract a list strings for list object name. Returns empty array if not found.
783
     * Assumes that there are no brackets '{' or '}' in the actual data.
784
     * @deprecated Prefer using the {@link JsonParser}
785
     * @param objectName object name
786
     * @param json source json
787
     * @return a string list, empty if no values are found.
788
     */
789
    @Deprecated
790
    public static List<String> getStringList(String objectName, String json) {
791
        String flat = json.replaceAll("\r", "").replaceAll("\n", "");
1✔
792
        Matcher m = string_array_pattern(objectName).matcher(flat);
1✔
793
        if (m.find()) {
1✔
794
            String arrayString = m.group(1);
1✔
795
            return toList(arrayString);
1✔
796
        }
797
        return new ArrayList<>();
1✔
798
    }
799

800
    private static List<String> toList(String arrayString) {
801
        List<String> list = new ArrayList<>();
1✔
802
        String[] raw = arrayString.split(",");
1✔
803
        for (String s : raw) {
1✔
804
            String cleaned = s.trim().replace("\"", "");
1✔
805
            if (cleaned.length() > 0) {
1✔
806
                list.add(jsonDecode(cleaned));
1✔
807
            }
808
        }
809
        return list;
1✔
810
    }
811

812
    /**
813
     * Extract a list longs for list object name. Returns empty array if not found.
814
     * @deprecated Prefer using the {@link JsonParser}
815
     * @param objectName object name
816
     * @param json source json
817
     * @return a long list, empty if no values are found.
818
     */
819
    @Deprecated
820
    public static List<Long> getLongList(String objectName, String json) {
821
        String flat = json.replaceAll("\r", "").replaceAll("\n", "");
1✔
822
        List<Long> list = new ArrayList<>();
1✔
823
        Matcher m = number_array_pattern(objectName).matcher(flat);
1✔
824
        if (m.find()) {
1✔
825
            String arrayString = m.group(1);
1✔
826
            String[] raw = arrayString.split(",");
1✔
827

828
            for (String s : raw) {
1✔
829
                list.add(safeParseLong(s.trim()));
1✔
830
            }
831
        }
832
        return list;
1✔
833
    }
834

835
    /**
836
     * Extract a list durations for list object name. Returns empty array if not found.
837
     * @param objectName object name
838
     * @param json source json
839
     * @return a duration list, empty if no values are found.
840
     */
841
    @Deprecated
842
    public static List<Duration> getDurationList(String objectName, String json) {
843
        List<Long> longs = getLongList(objectName, json);
1✔
844
        List<Duration> list = new ArrayList<>(longs.size());
1✔
845
        for (Long l : longs) {
1✔
846
            list.add(Duration.ofNanos(l));
1✔
847
        }
1✔
848
        return list;
1✔
849
    }
850

851
    @Deprecated
852
    public static byte[] simpleMessageBody(String name, Number value) {
853
        return (OPENQ + name + QCOLON + value + CLOSE).getBytes();
1✔
854
    }
855

856
    @Deprecated
857
    public static byte[] simpleMessageBody(String name, String value) {
858
        return (OPENQ + name + QCOLONQ + value + Q + CLOSE).getBytes();
1✔
859
    }
860

861
    @Deprecated
862
    public static String readString(String json, Pattern pattern) {
863
        return readString(json, pattern, null);
1✔
864
    }
865

866
    @Deprecated
867
    public static String readString(String json, Pattern pattern, String dflt) {
868
        Matcher m = pattern.matcher(json);
1✔
869
        return m.find() ? jsonDecode(m.group(1)) : dflt;
1✔
870
    }
871

872
    @Deprecated
873
    public static String readStringMayHaveQuotes(String json, String field, String dflt) {
874
        String jfield = "\"" + field + "\"";
1✔
875
        int at = json.indexOf(jfield);
1✔
876
        if (at != -1) {
1✔
877
            at = json.indexOf('"', at + jfield.length());
1✔
878
            StringBuilder sb = new StringBuilder();
1✔
879
            while (true) {
880
                char c = json.charAt(++at);
1✔
881
                if (c == '\\') {
1✔
882
                    char c2 = json.charAt(++at);
1✔
883
                    if (c2 == '"') {
1✔
884
                        sb.append('"');
1✔
885
                    }
886
                    else {
887
                        sb.append(c);
1✔
888
                        sb.append(c2);
1✔
889
                    }
890
                }
1✔
891
                else if (c == '"') {
1✔
892
                    break;
1✔
893
                }
894
                else {
895
                    sb.append(c);
1✔
896
                }
897
            }
1✔
898
            return jsonDecode(sb.toString());
1✔
899
        }
900
        return dflt;
1✔
901
    }
902

903
    @Deprecated
904
    public static byte[] readBytes(String json, Pattern pattern) {
905
        String s = readString(json, pattern, null);
1✔
906
        return s == null ? null : s.getBytes(StandardCharsets.UTF_8);
1✔
907
    }
908

909
    @Deprecated
910
    public static byte[] readBase64(String json, Pattern pattern) {
911
        Matcher m = pattern.matcher(json);
1✔
912
        String b64 = m.find() ? m.group(1) : null;
1✔
913
        return b64 == null ? null : Base64.getDecoder().decode(b64);
1✔
914
    }
915

916
    @Deprecated
917
    public static boolean readBoolean(String json, Pattern pattern) {
918
        Matcher m = pattern.matcher(json);
1✔
919
        return m.find() && Boolean.parseBoolean(m.group(1));
1✔
920
    }
921

922
    @Deprecated
923
    public static Boolean readBoolean(String json, Pattern pattern, Boolean dflt) {
924
        Matcher m = pattern.matcher(json);
1✔
925
        if (m.find()) {
1✔
926
            return Boolean.parseBoolean(m.group(1));
1✔
927
        }
928
        return dflt;
1✔
929
    }
930

931
    @Deprecated
932
    public static Integer readInteger(String json, Pattern pattern) {
933
        Matcher m = pattern.matcher(json);
1✔
934
        return m.find() ? Integer.parseInt(m.group(1)) : null;
1✔
935
    }
936

937
    @Deprecated
938
    public static int readInt(String json, Pattern pattern, int dflt) {
939
        Matcher m = pattern.matcher(json);
1✔
940
        return m.find() ? Integer.parseInt(m.group(1)) : dflt;
1✔
941
    }
942

943
    @Deprecated
944
    public static void readInt(String json, Pattern pattern, IntConsumer c) {
945
        Matcher m = pattern.matcher(json);
1✔
946
        if (m.find()) {
1✔
947
            c.accept(Integer.parseInt(m.group(1)));
1✔
948
        }
949
    }
1✔
950

951
    @Deprecated
952
    public static Long readLong(String json, Pattern pattern) {
953
        Matcher m = pattern.matcher(json);
1✔
954
        return m.find() ? safeParseLong(m.group(1)) : null;
1✔
955
    }
956

957
    @Deprecated
958
    public static long readLong(String json, Pattern pattern, long dflt) {
959
        Matcher m = pattern.matcher(json);
1✔
960
        return m.find() ? safeParseLong(m.group(1), dflt) : dflt;
1✔
961
    }
962

963
    @Deprecated
964
    public static void readLong(String json, Pattern pattern, LongConsumer c) {
965
        Matcher m = pattern.matcher(json);
1✔
966
        if (m.find()) {
1✔
967
            Long l = safeParseLong(m.group(1));
1✔
968
            if (l != null) {
1✔
969
                c.accept(l);
1✔
970
            }
971
        }
972
    }
1✔
973

974
    @Deprecated
975
    public static ZonedDateTime readDate(String json, Pattern pattern) {
976
        Matcher m = pattern.matcher(json);
1✔
977
        return m.find() ? DateTimeUtils.parseDateTime(m.group(1)) : null;
1✔
978
    }
979

980
    @Deprecated
981
    public static Duration readNanos(String json, Pattern pattern) {
982
        Matcher m = pattern.matcher(json);
1✔
983
        return m.find() ? Duration.ofNanos(Long.parseLong(m.group(1))) : null;
1✔
984
    }
985

986
    @Deprecated
987
    public static Duration readNanos(String json, Pattern pattern, Duration dflt) {
988
        Matcher m = pattern.matcher(json);
1✔
989
        return m.find() ? Duration.ofNanos(Long.parseLong(m.group(1))) : dflt;
1✔
990
    }
991

992
    @Deprecated
993
    public static void readNanos(String json, Pattern pattern, Consumer<Duration> c) {
994
        Matcher m = pattern.matcher(json);
1✔
995
        if (m.find()) {
1✔
996
            c.accept(Duration.ofNanos(Long.parseLong(m.group(1))));
1✔
997
        }
998
    }
1✔
999

1000
    public static <T> boolean listEquals(List<T> l1, List<T> l2)
1001
    {
1002
        if (l1 == null)
1✔
1003
        {
1004
            return l2 == null;
1✔
1005
        }
1006

1007
        if (l2 == null)
1✔
1008
        {
1009
            return false;
1✔
1010
        }
1011

1012
        return l1.equals(l2);
1✔
1013
    }
1014

1015
    public static boolean mapEquals(Map<String, String> map1, Map<String, String> map2) {
1016
        if (map1 == null) {
1✔
1017
            return map2 == null;
1✔
1018
        }
1019
        if (map2 == null || map1.size() != map2.size()) {
1✔
1020
            return false;
1✔
1021
        }
1022
        for (String key : map1.keySet()) {
1✔
1023
            if (!Objects.equals(map1.get(key), map2.get(key))) {
1✔
1024
                return false;
1✔
1025
            }
1026
        }
1✔
1027
        return true;
1✔
1028
    }
1029
}
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