Skip to content

Commit 5dd9187

Browse files
jasmith-hsclaude
andcommitted
Add fast-path and use Class keys in AllowlistReturnTypeValidator
String/Number/Boolean are always allowed return types, so skip the ConcurrentHashMap lookup entirely. Also changed the cache key from String (canonical class name) to Class<?> to avoid the cost of getCanonicalName() on cache hits. Benchmark: +64% throughput on complexTemplateBenchmark (3,316 -> 5,428 ops/s) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a14e03e commit 5dd9187

1 file changed

Lines changed: 15 additions & 10 deletions

File tree

src/main/java/com/hubspot/jinjava/el/ext/AllowlistReturnTypeValidator.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public final class AllowlistReturnTypeValidator {
1111
AllowlistReturnTypeValidator.create(
1212
ReturnTypeValidatorConfig.builder().addDefaultAllowlistGroups().build()
1313
);
14-
private final ConcurrentHashMap<String, Boolean> allowedReturnTypesCache;
14+
private final ConcurrentHashMap<Class<?>, Boolean> allowedReturnTypesCache;
1515

1616
private final ImmutableSet<String> allowedCanonicalClassPrefixes;
1717
private final ImmutableSet<String> allowedCanonicalClassNames;
@@ -47,20 +47,25 @@ public Object validateReturnType(Object o) {
4747
if (o == null) {
4848
return null;
4949
}
50+
if (o instanceof String || o instanceof Number || o instanceof Boolean) {
51+
return o;
52+
}
5053
Class<?> clazz = o.getClass();
5154
if (clazz.isArray() && allowArrays) {
5255
return o;
5356
}
54-
String canonicalClassName = clazz.getCanonicalName();
55-
if (canonicalClassName == null) {
56-
onRejectedClass.accept(clazz);
57-
return null;
58-
}
5957
boolean isAllowedClassName = allowedReturnTypesCache.computeIfAbsent(
60-
canonicalClassName,
61-
c ->
62-
allowedCanonicalClassNames.contains(canonicalClassName) ||
63-
allowedCanonicalClassPrefixes.stream().anyMatch(canonicalClassName::startsWith)
58+
clazz,
59+
c -> {
60+
String canonicalClassName = c.getCanonicalName();
61+
if (canonicalClassName == null) {
62+
return false;
63+
}
64+
return (
65+
allowedCanonicalClassNames.contains(canonicalClassName) ||
66+
allowedCanonicalClassPrefixes.stream().anyMatch(canonicalClassName::startsWith)
67+
);
68+
}
6469
);
6570
if (!isAllowedClassName) {
6671
onRejectedClass.accept(clazz);

0 commit comments

Comments
 (0)