Skip to content

Commit 9d353b8

Browse files
rbygraveSentryMan
andauthored
Refactor CoreAdapterBuilder cache use (#276)
* Refactor CoreAdapterBuilder cache use We can merge the 2 build() methods because the cacheKey is always just the type. * The key for adapterCache can be Type rather than Object * Refactor CoreAdapterBuilder to put ValidationAdapters into the cache Previously, it always created new adapters and didn't actually use the adapterCache. --------- Co-authored-by: Josiah Noel <32279667+SentryMan@users.noreply.github.com>
1 parent 1205844 commit 9d353b8

File tree

3 files changed

+29
-27
lines changed

3 files changed

+29
-27
lines changed

validator/src/main/java/io/avaje/validation/core/CoreAdapterBuilder.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ final class CoreAdapterBuilder {
3131
private final DValidator context;
3232
private final List<AdapterFactory> factories = new ArrayList<>();
3333
private final List<AnnotationFactory> annotationFactories = new ArrayList<>();
34-
private final Map<Object, ValidationAdapter<?>> adapterCache = new ConcurrentHashMap<>();
34+
private final Map<Type, ValidationAdapter<?>> adapterCache = new ConcurrentHashMap<>();
3535

3636
CoreAdapterBuilder(
3737
DValidator context,
@@ -50,26 +50,21 @@ final class CoreAdapterBuilder {
5050
this.annotationFactories.add(new FuturePastAdapterFactory(clockSupplier, temporalTolerance));
5151
}
5252

53-
/** Return the adapter from cache if exists else return null. */
53+
/** Return the adapter from cache if exists creating the adapter if required. */
5454
@SuppressWarnings("unchecked")
55-
<T> ValidationAdapter<T> get(Object cacheKey) {
56-
return (ValidationAdapter<T>) adapterCache.get(cacheKey);
57-
}
58-
59-
/** Build for the simple non-annotated type case. */
6055
<T> ValidationAdapter<T> build(Type type) {
61-
return build(type, type);
62-
}
63-
64-
<T> ValidationAdapter<T> annotationAdapter(
65-
Class<? extends Annotation> cls, Map<String, Object> attributes, Set<Class<?>> groups) {
66-
return buildAnnotation(cls, attributes, groups);
56+
var adapter = adapterCache.get(type);
57+
if (adapter != null) {
58+
return (ValidationAdapter<T>)adapter;
59+
}
60+
ValidationAdapter<T> newValidator = buildForType(type);
61+
adapterCache.put(type, newValidator);
62+
return newValidator;
6763
}
6864

69-
/** Build given type and annotations. */
70-
// TODO understand that lookup chain stuff
65+
/** Build for the simple non-annotated type case. */
7166
@SuppressWarnings("unchecked")
72-
<T> ValidationAdapter<T> build(Type type, Object cacheKey) {
67+
private <T> ValidationAdapter<T> buildForType(Type type) {
7368
// Ask each factory to create the validation adapter.
7469
for (final AdapterFactory factory : factories) {
7570
final var result = (ValidationAdapter<T>) factory.create(type, context);
@@ -80,6 +75,11 @@ <T> ValidationAdapter<T> build(Type type, Object cacheKey) {
8075
throw new IllegalArgumentException("No ValidationAdapter for " + type + ". Perhaps needs @Valid or @Valid.Import?");
8176
}
8277

78+
<T> ValidationAdapter<T> annotationAdapter(
79+
Class<? extends Annotation> cls, Map<String, Object> attributes, Set<Class<?>> groups) {
80+
return buildAnnotation(cls, attributes, groups);
81+
}
82+
8383
/**
8484
* Build given type and annotations.
8585
*

validator/src/main/java/io/avaje/validation/core/DValidator.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,6 @@ public Message message(String message, Map<String, Object> attributes) {
126126
@Override
127127
public <T> ValidationAdapter<T> adapter(Class<T> cls) {
128128
final Type cacheKey = canonicalizeClass(requireNonNull(cls));
129-
final ValidationAdapter<T> result = builder.get(cacheKey);
130-
if (result != null) {
131-
return result;
132-
}
133129
return builder.build(cacheKey);
134130
}
135131

@@ -152,13 +148,8 @@ public <T> ValidationAdapter<T> adapter(
152148

153149
@Override
154150
public <T> ValidationAdapter<T> adapter(Type type) {
155-
type = removeSubtypeWildcard(canonicalize(requireNonNull(type)));
156-
final Object cacheKey = type;
157-
final ValidationAdapter<T> result = builder.get(cacheKey);
158-
if (result != null) {
159-
return result;
160-
}
161-
return builder.build(type, cacheKey);
151+
final Type cacheKey = removeSubtypeWildcard(canonicalize(requireNonNull(type)));
152+
return builder.build(cacheKey);
162153
}
163154

164155
@Override

validator/src/test/java/io/avaje/validation/core/ValidatorTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import io.avaje.validation.ConstraintViolation;
44
import io.avaje.validation.ConstraintViolationException;
55
import io.avaje.validation.Validator;
6+
import io.avaje.validation.adapter.ValidationAdapter;
7+
import io.avaje.validation.adapter.ValidationContext;
68
import org.junit.jupiter.api.Test;
79

810
import java.time.LocalDate;
@@ -22,6 +24,15 @@ class ValidatorTest {
2224
.add(Contact.class, ContactValidationAdapter::new)
2325
.build();
2426

27+
@Test
28+
void cacheForType() {
29+
ValidationContext ctx = (ValidationContext) validator;
30+
31+
ValidationAdapter<Customer> adapter0 = ctx.adapter(Customer.class);
32+
ValidationAdapter<Customer> adapter1 = ctx.adapter(Customer.class);
33+
assertThat(adapter0).isSameAs(adapter1);
34+
}
35+
2536
@Test
2637
void testAllFail() {
2738
try {

0 commit comments

Comments
 (0)