Skip to content

Commit 1b79eeb

Browse files
Polishing.
Use double checked locking to be as close to the previous implementation but still benefit from the fast read operation. Original Pull Request: #3186
1 parent adc8e3f commit 1b79eeb

File tree

3 files changed

+57
-28
lines changed

3 files changed

+57
-28
lines changed

src/main/java/org/springframework/data/convert/CustomConversions.java

+27-10
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ private Class<?> getCustomTarget(Class<?> sourceType, @Nullable Class<?> targetT
497497
*/
498498
static class ConversionTargetsCache {
499499

500-
private Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>();
500+
private volatile Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>();
501501

502502
/**
503503
* Get or compute a target type given its {@code sourceType}. Returns a cached {@link Optional} if the value
@@ -531,10 +531,19 @@ public Class<?> computeIfAbsent(Class<?> sourceType, Class<?> targetType,
531531

532532
if (targetTypes == null) {
533533

534-
Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>(this.customReadTargetTypes);
535-
targetTypes = new TargetTypes(sourceType);
536-
customReadTargetTypes.put(sourceType, targetTypes);
537-
this.customReadTargetTypes = customReadTargetTypes;
534+
synchronized (this) {
535+
536+
TargetTypes customReadTarget = customReadTargetTypes.get(sourceType);
537+
if (customReadTarget != null) {
538+
targetTypes = customReadTarget;
539+
} else {
540+
541+
Map<Class<?>, TargetTypes> customReadTargetTypes = new HashMap<>(this.customReadTargetTypes);
542+
targetTypes = new TargetTypes(sourceType);
543+
customReadTargetTypes.put(sourceType, targetTypes);
544+
this.customReadTargetTypes = customReadTargetTypes;
545+
}
546+
}
538547
}
539548

540549
return targetTypes.computeIfAbsent(targetType, mappingFunction);
@@ -554,7 +563,7 @@ interface AbsentTargetTypeMarker {}
554563
static class TargetTypes {
555564

556565
private final Class<?> sourceType;
557-
private Map<Class<?>, Class<?>> conversionTargets = new HashMap<>();
566+
private volatile Map<Class<?>, Class<?>> conversionTargets = new HashMap<>();
558567

559568
TargetTypes(Class<?> sourceType) {
560569
this.sourceType = sourceType;
@@ -576,11 +585,19 @@ public Class<?> computeIfAbsent(Class<?> targetType, Function<ConvertiblePair, C
576585

577586
if (optionalTarget == null) {
578587

579-
optionalTarget = mappingFunction.apply(new ConvertiblePair(sourceType, targetType));
588+
synchronized (this) {
589+
590+
Class<?> conversionTarget = conversionTargets.get(targetType);
591+
if (conversionTarget != null) {
592+
optionalTarget = conversionTarget;
593+
} else {
580594

581-
Map<Class<?>, Class<?>> conversionTargets = new HashMap<>(this.conversionTargets);
582-
conversionTargets.put(targetType, optionalTarget == null ? Void.class : optionalTarget);
583-
this.conversionTargets = conversionTargets;
595+
optionalTarget = mappingFunction.apply(new ConvertiblePair(sourceType, targetType));
596+
Map<Class<?>, Class<?>> conversionTargets = new HashMap<>(this.conversionTargets);
597+
conversionTargets.put(targetType, optionalTarget == null ? Void.class : optionalTarget);
598+
this.conversionTargets = conversionTargets;
599+
}
600+
}
584601
}
585602

586603
return Void.class.equals(optionalTarget) ? null : optionalTarget;

src/main/java/org/springframework/data/convert/SimplePropertyValueConversions.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class SimplePropertyValueConversions implements PropertyValueConversions,
5353

5454
private @Nullable ValueConverterRegistry<?> valueConverterRegistry;
5555

56-
private Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>();
56+
private volatile Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>();
5757

5858
@SuppressWarnings("rawtypes")
5959
enum NoOpConverter implements PropertyValueConverter {
@@ -171,17 +171,21 @@ private <DV, SV, P extends PersistentProperty<P>, D extends ValueConversionConte
171171

172172
if (converter == null) {
173173

174-
converter = requireConverterFactory().getConverter(property);
174+
synchronized (this) {
175175

176-
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>(this.converterCache);
176+
PropertyValueConverter<?, ?, ?> fromCache = converterCache.get(property);
177+
if (fromCache != null) {
178+
converter = fromCache;
179+
} else {
177180

178-
if (converter == null) {
179-
converterCache.put(property, NoOpConverter.INSTANCE);
180-
} else {
181-
converterCache.put(property, converter);
182-
}
181+
converter = requireConverterFactory().getConverter(property);
183182

184-
this.converterCache = converterCache;
183+
Map<PersistentProperty<?>, PropertyValueConverter<?, ?, ?>> converterCache = new HashMap<>(
184+
this.converterCache);
185+
converterCache.put(property, converter != null ? converter : NoOpConverter.INSTANCE);
186+
this.converterCache = converterCache;
187+
}
188+
}
185189
}
186190

187191
if (converter == NoOpConverter.INSTANCE) {

src/main/java/org/springframework/data/mapping/InstanceCreatorMetadataSupport.java

+17-9
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class InstanceCreatorMetadataSupport<T, P extends PersistentProperty<P>> impleme
3535

3636
private final Executable executable;
3737
private final List<Parameter<Object, P>> parameters;
38-
private Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>();
38+
private volatile Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>();
3939

4040
/**
4141
* Creates a new {@link InstanceCreatorMetadataSupport} from the given {@link Executable} and {@link Parameter}s.
@@ -90,17 +90,25 @@ public boolean isCreatorParameter(PersistentProperty<?> property) {
9090

9191
Boolean cached = isPropertyParameterCache.get(property);
9292

93-
if (cached != null) {
94-
return cached;
95-
}
93+
if (cached == null) {
94+
95+
synchronized (this) {
96+
97+
Boolean fromCache = isPropertyParameterCache.get(property);
98+
if (fromCache != null) {
99+
cached = fromCache;
100+
} else {
96101

97-
boolean result = doGetIsCreatorParameter(property);
102+
cached = doGetIsCreatorParameter(property);
98103

99-
Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>(this.isPropertyParameterCache);
100-
isPropertyParameterCache.put(property, result);
101-
this.isPropertyParameterCache = isPropertyParameterCache;
104+
Map<PersistentProperty<?>, Boolean> isPropertyParameterCache = new HashMap<>(this.isPropertyParameterCache);
105+
isPropertyParameterCache.put(property, cached);
106+
this.isPropertyParameterCache = isPropertyParameterCache;
107+
}
108+
}
109+
}
102110

103-
return result;
111+
return cached;
104112
}
105113

106114
@Override

0 commit comments

Comments
 (0)