From b12a4801ffd5206771c0f9e33f05029a67bc5604 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 3 Oct 2024 11:59:03 -0700 Subject: [PATCH] Polish BasicJsonParser --- .../boot/json/BasicJsonParser.java | 70 +++++++++++++------ 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java index 419190589a..05c1b5d278 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java @@ -17,6 +17,7 @@ package org.springframework.boot.json; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -123,38 +124,33 @@ public class BasicJsonParser extends AbstractJsonParser { private List tokenize(String json) { List list = new ArrayList<>(); - int index = 0; - int inObject = 0; - int inList = 0; - boolean inValue = false; - boolean inEscape = false; + Tracking tracking = new Tracking(); StringBuilder build = new StringBuilder(); + int index = 0; while (index < json.length()) { - char current = json.charAt(index); - if (inEscape) { - build.append(current); + char ch = json.charAt(index); + if (tracking.in(Tracked.ESCAPE)) { + build.append(ch); index++; - inEscape = false; + tracking.set(Tracked.ESCAPE, 0); continue; } - switch (current) { - case '{' -> inObject++; - case '}' -> inObject--; - case '[' -> inList++; - case ']' -> inList--; + 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 (current == '"') { - inValue = !inValue; - } - if (current == ',' && inObject == 0 && inList == 0 && !inValue) { + if (ch == ',' && !tracking.in(Tracked.OBJECT, Tracked.LIST, Tracked.VALUE)) { list.add(build.toString()); build.setLength(0); } - else if (current == '\\') { - inEscape = true; + else if (ch == '\\') { + tracking.set(Tracked.ESCAPE, 1); } else { - build.append(current); + build.append(ch); } index++; } @@ -164,4 +160,36 @@ public class BasicJsonParser extends AbstractJsonParser { 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 + + } + }