Skip to content

Commit 3dbbb15

Browse files
mp911deodrotbohm
authored andcommitted
DATACMNS-1101 - Use dedicated type to cache custom conversion targets without requested target type.
We now use a marker interface to store cache hits for conversion targets without requesting a conversion target in the conversion query. The dedicated marker type has an individual cache view and does not interfere with other types. Previously we used Object as cache key which caused false positives due to assignability checks. If an earlier conversion query with a requested target type yielded a hit (e.g. negative hit), subsequent queries without a target type received the same answer. This might happen although the non-cached answer would return a different result.
1 parent f6a6565 commit 3dbbb15

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ static class ConversionTargetsCache {
372372
*/
373373
public Optional<Class<?>> computeIfAbsent(Class<?> sourceType,
374374
Function<ConvertiblePair, Optional<Class<?>>> mappingFunction) {
375-
return computeIfAbsent(sourceType, Object.class, mappingFunction);
375+
return computeIfAbsent(sourceType, AbsentTargetTypeMarker.class, mappingFunction);
376376
}
377377

378378
/**
@@ -391,6 +391,11 @@ public Optional<Class<?>> computeIfAbsent(Class<?> sourceType, Class<?> targetTy
391391
TargetTypes targetTypes = customReadTargetTypes.computeIfAbsent(sourceType, TargetTypes::new);
392392
return targetTypes.computeIfAbsent(targetType, mappingFunction);
393393
}
394+
395+
/**
396+
* Marker type for absent target type caching.
397+
*/
398+
interface AbsentTargetTypeMarker {}
394399
}
395400

396401
/**

src/test/java/org/springframework/data/convert/CustomConversionsUnitTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
*
4545
* @author Oliver Gierke
4646
* @author Christoph Strobl
47+
* @author Mark Paluch
4748
* @since 2.0
4849
*/
4950
public class CustomConversionsUnitTests {
@@ -71,6 +72,17 @@ public void considersSubtypesCorrectly() {
7172
assertThat(conversions.hasCustomReadTarget(String.class, Long.class)).isTrue();
7273
}
7374

75+
@Test // DATACMNS-1101
76+
public void considersSubtypeCachingCorrectly() {
77+
78+
CustomConversions conversions = new CustomConversions(StoreConversions.NONE,
79+
Arrays.asList(NumberToStringConverter.INSTANCE, StringToNumberConverter.INSTANCE));
80+
81+
assertThat(conversions.getCustomWriteTarget(Long.class, Object.class)).isEmpty();
82+
assertThat(conversions.getCustomWriteTarget(Long.class)).hasValue(String.class);
83+
assertThat(conversions.getCustomWriteTarget(Long.class, Object.class)).isEmpty();
84+
}
85+
7486
@Test // DATACMNS-1035
7587
public void populatesConversionServiceCorrectly() {
7688

0 commit comments

Comments
 (0)