BasicJsonParser Class — spring-boot Architecture
Architecture documentation for the BasicJsonParser class in BasicJsonParser.java from the spring-boot codebase.
Entity Profile
Source Code
core/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java lines 42–203
public class BasicJsonParser extends AbstractJsonParser {
private static final int MAX_DEPTH = 1000;
@Override
public Map<String, Object> parseMap(@Nullable String json) {
return tryParse(() -> parseMap(json, (jsonToParse) -> parseMapInternal(0, jsonToParse)), Exception.class);
}
@Override
public List<Object> parseList(@Nullable String json) {
return tryParse(() -> parseList(json, (jsonToParse) -> parseListInternal(0, jsonToParse)), Exception.class);
}
private List<Object> parseListInternal(int nesting, String json) {
List<Object> list = new ArrayList<>();
json = trimEdges(json, '[', ']').trim();
for (String value : tokenize(json)) {
list.add(parseInternal(nesting + 1, value));
}
return list;
}
private Object parseInternal(int nesting, String json) {
if (nesting > MAX_DEPTH) {
throw new IllegalStateException("JSON is too deeply nested");
}
if (json.startsWith("[")) {
return parseListInternal(nesting + 1, json);
}
if (json.startsWith("{")) {
return parseMapInternal(nesting + 1, json);
}
if (json.startsWith("\"")) {
return trimEdges(json, '"', '"');
}
return parseNumber(json);
}
private Map<String, Object> parseMapInternal(int nesting, String json) {
Map<String, Object> map = new LinkedHashMap<>();
json = trimEdges(json, '{', '}').trim();
for (String pair : tokenize(json)) {
String[] split = StringUtils.split(pair, ":");
@Nullable String[] values = (split != null) ? StringUtils.trimArrayElements(split) : null;
Assert.state(values != null, () -> "Unable to parse '%s'".formatted(pair));
String rawKey = values[0];
String rawValue = values[1];
Assert.state(rawKey != null, () -> "rawKew is null in '%s'".formatted(pair));
Assert.state(rawKey.startsWith("\"") && rawKey.endsWith("\""),
"Expecting double-quotes around field names");
String key = trimEdges(rawKey, '"', '"');
Assert.state(rawValue != null, () -> "rawValue is null in '%s'".formatted(pair));
Object value = parseInternal(nesting, rawValue);
map.put(key, value);
}
return map;
}
private Object parseNumber(String json) {
try {
return Long.valueOf(json);
}
catch (NumberFormatException ex) {
try {
return Double.valueOf(json);
}
catch (NumberFormatException ex2) {
return json;
}
}
}
private static String trimTrailingCharacter(String string, char c) {
if (!string.isEmpty() && string.charAt(string.length() - 1) == c) {
return string.substring(0, string.length() - 1);
}
return string;
}
private static String trimLeadingCharacter(String string, char c) {
if (!string.isEmpty() && string.charAt(0) == c) {
return string.substring(1);
}
return string;
}
private static String trimEdges(String string, char leadingChar, char trailingChar) {
return trimTrailingCharacter(trimLeadingCharacter(string, leadingChar), trailingChar);
}
private List<String> tokenize(String json) {
List<String> list = new ArrayList<>();
Tracking tracking = new Tracking();
StringBuilder build = new StringBuilder();
int index = 0;
while (index < json.length()) {
char ch = json.charAt(index);
if (tracking.in(Tracked.ESCAPE)) {
build.append(ch);
index++;
tracking.set(Tracked.ESCAPE, 0);
continue;
}
switch (ch) {
case '{' -> tracking.update(Tracked.OBJECT, +1);
case '}' -> tracking.update(Tracked.OBJECT, -1);
case '[' -> tracking.update(Tracked.LIST, +1);
case ']' -> tracking.update(Tracked.LIST, -1);
case '"' -> tracking.toggle(Tracked.VALUE);
}
if (ch == ',' && !tracking.in(Tracked.OBJECT, Tracked.LIST, Tracked.VALUE)) {
list.add(build.toString());
build.setLength(0);
}
else if (ch == '\\') {
tracking.set(Tracked.ESCAPE, 1);
}
else {
build.append(ch);
}
index++;
}
if (!build.isEmpty()) {
list.add(build.toString().trim());
}
return list;
}
private static final class Tracking {
private final int[] counts = new int[Tracked.values().length];
boolean in(Tracked... tracked) {
return Arrays.stream(tracked).mapToInt(this::get).anyMatch((i) -> i > 0);
}
void toggle(Tracked tracked) {
set(tracked, (get(tracked) != 0) ? 0 : 1);
}
void update(Tracked tracked, int delta) {
set(tracked, get(tracked) + delta);
}
private int get(Tracked tracked) {
return this.counts[tracked.ordinal()];
}
void set(Tracked tracked, int count) {
this.counts[tracked.ordinal()] = count;
}
}
private enum Tracked {
OBJECT, LIST, VALUE, ESCAPE
}
}
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free