Skip to content

Commit f3b3801

Browse files
DATACMNS-1615 - Allow deferred converter configuration.
Add a Supplier variant for constructing new CustomConversions. This allows store implementations to hook into the actual configuration based on user code. Required for messing with store specific simple type registration based on user decisions.
1 parent 580e55a commit f3b3801

File tree

1 file changed

+110
-27
lines changed

1 file changed

+110
-27
lines changed

Diff for: src/main/java/org/springframework/data/convert/CustomConversions.java

+110-27
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,19 @@
2222
import lombok.Value;
2323
import lombok.extern.slf4j.Slf4j;
2424

25-
import java.util.*;
25+
import java.util.ArrayList;
26+
import java.util.Arrays;
27+
import java.util.Collection;
28+
import java.util.Collections;
29+
import java.util.HashSet;
30+
import java.util.LinkedHashSet;
31+
import java.util.List;
32+
import java.util.Map;
33+
import java.util.Optional;
34+
import java.util.Set;
2635
import java.util.concurrent.ConcurrentHashMap;
2736
import java.util.function.Function;
37+
import java.util.function.Supplier;
2838
import java.util.stream.Collectors;
2939

3040
import org.springframework.core.GenericTypeResolver;
@@ -84,6 +94,8 @@ public class CustomConversions {
8494
private final ConversionTargetsCache customReadTargetTypes = new ConversionTargetsCache();
8595
private final ConversionTargetsCache customWriteTargetTypes = new ConversionTargetsCache();
8696

97+
private final ConverterConfiguration converterConfiguration;
98+
8799
private final Function<ConvertiblePair, Class<?>> getReadTarget = convertiblePair -> getCustomTarget(
88100
convertiblePair.getSourceType(), convertiblePair.getTargetType(), readingPairs);
89101

@@ -93,6 +105,41 @@ public class CustomConversions {
93105
private Function<ConvertiblePair, Class<?>> getRawWriteTarget = convertiblePair -> getCustomTarget(
94106
convertiblePair.getSourceType(), null, writingPairs);
95107

108+
/**
109+
* Deferred initialization allowing store implementations use a callback/consumer driven configuration of the actual
110+
* {@link CustomConversions}.
111+
*
112+
* @param converterConfiguration the {@link Supplier} providing a {@link ConverterConfiguration}.
113+
* @since 2.3
114+
*/
115+
protected CustomConversions(Supplier<ConverterConfiguration> converterConfiguration) {
116+
this(converterConfiguration.get());
117+
}
118+
119+
/**
120+
* @param converterConfiguration the {@link ConverterConfiguration} to apply.
121+
* @since 2.3
122+
*/
123+
protected CustomConversions(ConverterConfiguration converterConfiguration) {
124+
125+
this.converterConfiguration = converterConfiguration;
126+
127+
List<Object> registeredConverters = collectPotentialConverterRegistrations(
128+
converterConfiguration.getStoreConversions(), converterConfiguration.getUserConverters()).stream() //
129+
.filter(this::isSupportedConverter) //
130+
.filter(it -> !skip(it)) //
131+
.map(ConverterRegistrationIntent::getConverterRegistration) //
132+
.map(this::register) //
133+
.distinct() //
134+
.collect(Collectors.toList());
135+
136+
Collections.reverse(registeredConverters);
137+
138+
this.converters = Collections.unmodifiableList(registeredConverters);
139+
this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes,
140+
converterConfiguration.getStoreConversions().getStoreTypeHolder());
141+
}
142+
96143
/**
97144
* Creates a new {@link CustomConversions} instance registering all given user defined converters and selecting
98145
* {@link Converter converters} from {@link StoreConversions} depending on
@@ -103,47 +150,34 @@ public class CustomConversions {
103150
* @param converters must not be {@literal null}.
104151
*/
105152
public CustomConversions(StoreConversions storeConversions, Collection<?> converters) {
106-
107-
Assert.notNull(storeConversions, "StoreConversions must not be null!");
108-
Assert.notNull(converters, "List of converters must not be null!");
109-
110-
List<Object> registeredConverters = collectPotentialConverterRegistrations(storeConversions, converters).stream() //
111-
.filter(this::isSupportedConverter) //
112-
.map(ConverterRegistrationIntent::getConverterRegistration) //
113-
.map(this::register) //
114-
.distinct() //
115-
.collect(Collectors.toList());
116-
117-
Collections.reverse(registeredConverters);
118-
119-
this.converters = Collections.unmodifiableList(registeredConverters);
120-
this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes, storeConversions.getStoreTypeHolder());
153+
this(new ConverterConfiguration(storeConversions, new ArrayList<>(converters)));
121154
}
122155

123156
/**
124157
* Validate a given {@link ConverterRegistration} in a specific setup. <br />
125158
* Non {@link ReadingConverter reading} and user defined {@link Converter converters} are only considered supported if
126159
* the {@link ConverterRegistrationIntent#isSimpleTargetType() target type} is considered to be a store simple type.
127160
*
128-
* @param registration
129-
* @return
161+
* @param registrationIntent
162+
* @return {@literal true} if supported.
130163
* @since 2.3
131164
*/
132-
protected boolean isSupportedConverter(ConverterRegistrationIntent registration) {
165+
protected boolean isSupportedConverter(ConverterRegistrationIntent registrationIntent) {
133166

134-
boolean register = registration.isUserConverter() || (registration.isReading() && registration.isSimpleSourceType())
135-
|| (registration.isWriting() && registration.isSimpleTargetType());
167+
boolean register = registrationIntent.isUserConverter()
168+
|| (registrationIntent.isReading() && registrationIntent.isSimpleSourceType())
169+
|| (registrationIntent.isWriting() && registrationIntent.isSimpleTargetType());
136170

137171
if (LOG.isDebugEnabled()) {
138172

139173
if (register) {
140-
LOG.debug(String.format(ADD_CONVERTER, registration.isUserConverter() ? "user defined " : "",
141-
registration.getSourceType(), registration.getTargetType(),
142-
registration.isReading() ? "reading" : "writing"));
174+
LOG.debug(String.format(ADD_CONVERTER, registrationIntent.isUserConverter() ? "user defined " : "",
175+
registrationIntent.getSourceType(), registrationIntent.getTargetType(),
176+
registrationIntent.isReading() ? "reading" : "writing"));
143177
} else {
144-
LOG.debug(String.format(SKIP_CONVERTER, registration.getSourceType(), registration.getTargetType(),
145-
registration.isReading() ? "reading" : "writing",
146-
registration.isReading() ? registration.getSourceType() : registration.getTargetType()));
178+
LOG.debug(String.format(SKIP_CONVERTER, registrationIntent.getSourceType(), registrationIntent.getTargetType(),
179+
registrationIntent.isReading() ? "reading" : "writing",
180+
registrationIntent.isReading() ? registrationIntent.getSourceType() : registrationIntent.getTargetType()));
147181
}
148182
}
149183

@@ -285,6 +319,17 @@ private Object register(ConverterRegistration converterRegistration) {
285319
return converterRegistration.getConverter();
286320
}
287321

322+
/**
323+
* @param intent must not be {@literal null}.
324+
* @return {@literal true} if the given {@link ConverterRegistration} shall be skipped.
325+
* @since 2.3
326+
*/
327+
private boolean skip(ConverterRegistrationIntent intent) {
328+
329+
return intent.isDefaultConveter()
330+
&& converterConfiguration.getSkipFor().contains(intent.getConverterRegistration().getConvertiblePair());
331+
}
332+
288333
/**
289334
* Returns the target type to convert to in case we have a custom conversion registered to convert the given source
290335
* type into a Mongo native one.
@@ -765,4 +810,42 @@ private boolean isStoreSimpleType(Class<?> type) {
765810
return storeTypeHolder.isSimpleType(type);
766811
}
767812
}
813+
814+
/**
815+
* Value object holding the actual {@link StoreConversions} and custom {@link Converter converters} configured for
816+
* registration.
817+
*
818+
* @author Christoph Strobl
819+
* @since 2.3
820+
*/
821+
protected static class ConverterConfiguration {
822+
823+
private final StoreConversions storeConversions;
824+
private final List<?> userConverters;
825+
private final Set<ConvertiblePair> skipFor;
826+
827+
public ConverterConfiguration(StoreConversions storeConversions, List<?> userConverters) {
828+
this(storeConversions, userConverters, Collections.emptySet());
829+
}
830+
831+
public ConverterConfiguration(StoreConversions storeConversions, List<?> userConverters,
832+
Collection<ConvertiblePair> skipFor) {
833+
834+
this.storeConversions = storeConversions;
835+
this.userConverters = new ArrayList<>(userConverters);
836+
this.skipFor = new HashSet<>(skipFor);
837+
}
838+
839+
StoreConversions getStoreConversions() {
840+
return storeConversions;
841+
}
842+
843+
List<?> getUserConverters() {
844+
return userConverters;
845+
}
846+
847+
Set<ConvertiblePair> getSkipFor() {
848+
return skipFor;
849+
}
850+
}
768851
}

0 commit comments

Comments
 (0)