Skip to content

Commit 3abc1ce

Browse files
thcedclaude
andcommitted
perf: Pre-build ref->component index in Spec (W3)
resolveSchema/resolveParameter previously rebuilt the component name via String.substring on every call. Build a Map keyed by the full $ref string at construction time so resolution is a single lookup with no per-request allocation. Removes ~150 MB of String/byte[] allocs per JFR run; tightens the validator hot path when schemas use \$ref. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6155853 commit 3abc1ce

2 files changed

Lines changed: 21 additions & 7 deletions

File tree

src/main/java/com/retailsvc/http/spec/Spec.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ public record Spec(
1717
List<Operation> operations,
1818
Map<String, Schema> componentSchemas,
1919
Map<String, Parameter> componentParameters,
20-
String basePath) {
20+
String basePath,
21+
Map<String, Schema> schemaRefIndex,
22+
Map<String, Parameter> parameterRefIndex) {
2123

2224
private static final String SCHEMA_KEY = "schema";
25+
private static final String SCHEMA_REF_PREFIX = "#/components/schemas/";
26+
private static final String PARAMETER_REF_PREFIX = "#/components/parameters/";
2327

2428
@SuppressWarnings("unchecked")
2529
public static Spec from(Map<String, Object> raw) {
@@ -40,7 +44,9 @@ public static Spec from(Map<String, Object> raw) {
4044
operations,
4145
componentSchemas,
4246
componentParameters,
43-
computeBasePath(servers));
47+
computeBasePath(servers),
48+
indexByRef(componentSchemas, SCHEMA_REF_PREFIX),
49+
indexByRef(componentParameters, PARAMETER_REF_PREFIX));
4450
}
4551

4652
private static String computeBasePath(List<Server> servers) {
@@ -50,18 +56,24 @@ private static String computeBasePath(List<Server> servers) {
5056
return Optional.ofNullable(URI.create(servers.getFirst().url()).getPath()).orElse("");
5157
}
5258

59+
private static <T> Map<String, T> indexByRef(Map<String, T> components, String prefix) {
60+
Map<String, T> out = new LinkedHashMap<>(components.size());
61+
for (var e : components.entrySet()) {
62+
out.put(prefix + e.getKey(), e.getValue());
63+
}
64+
return Map.copyOf(out);
65+
}
66+
5367
public Schema resolveSchema(String ref) {
54-
String name = stripPrefix(ref, "#/components/schemas/");
55-
Schema s = componentSchemas.get(name);
68+
Schema s = schemaRefIndex.get(ref);
5669
if (s == null) {
5770
throw new IllegalArgumentException("unknown schema ref: " + ref);
5871
}
5972
return s;
6073
}
6174

6275
public Parameter resolveParameter(String ref) {
63-
String name = stripPrefix(ref, "#/components/parameters/");
64-
Parameter p = componentParameters.get(name);
76+
Parameter p = parameterRefIndex.get(ref);
6577
if (p == null) {
6678
throw new IllegalArgumentException("unknown parameter ref: " + ref);
6779
}

src/test/java/com/retailsvc/http/internal/RequestPreparationFilterTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ private Spec specWith(Operation... ops) {
5050
List.of(ops),
5151
Map.of(),
5252
Map.of(),
53-
"");
53+
"",
54+
Map.of(),
55+
Map.of());
5456
}
5557

5658
private Filter newFilter(Spec spec) {

0 commit comments

Comments
 (0)