22
22
import lombok .Value ;
23
23
import lombok .extern .slf4j .Slf4j ;
24
24
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 ;
26
35
import java .util .concurrent .ConcurrentHashMap ;
27
36
import java .util .function .Function ;
37
+ import java .util .function .Supplier ;
28
38
import java .util .stream .Collectors ;
29
39
30
40
import org .springframework .core .GenericTypeResolver ;
@@ -84,6 +94,8 @@ public class CustomConversions {
84
94
private final ConversionTargetsCache customReadTargetTypes = new ConversionTargetsCache ();
85
95
private final ConversionTargetsCache customWriteTargetTypes = new ConversionTargetsCache ();
86
96
97
+ private final ConverterConfiguration converterConfiguration ;
98
+
87
99
private final Function <ConvertiblePair , Class <?>> getReadTarget = convertiblePair -> getCustomTarget (
88
100
convertiblePair .getSourceType (), convertiblePair .getTargetType (), readingPairs );
89
101
@@ -93,6 +105,41 @@ public class CustomConversions {
93
105
private Function <ConvertiblePair , Class <?>> getRawWriteTarget = convertiblePair -> getCustomTarget (
94
106
convertiblePair .getSourceType (), null , writingPairs );
95
107
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
+
96
143
/**
97
144
* Creates a new {@link CustomConversions} instance registering all given user defined converters and selecting
98
145
* {@link Converter converters} from {@link StoreConversions} depending on
@@ -103,47 +150,34 @@ public class CustomConversions {
103
150
* @param converters must not be {@literal null}.
104
151
*/
105
152
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 )));
121
154
}
122
155
123
156
/**
124
157
* Validate a given {@link ConverterRegistration} in a specific setup. <br />
125
158
* Non {@link ReadingConverter reading} and user defined {@link Converter converters} are only considered supported if
126
159
* the {@link ConverterRegistrationIntent#isSimpleTargetType() target type} is considered to be a store simple type.
127
160
*
128
- * @param registration
129
- * @return
161
+ * @param registrationIntent
162
+ * @return {@literal true} if supported.
130
163
* @since 2.3
131
164
*/
132
- protected boolean isSupportedConverter (ConverterRegistrationIntent registration ) {
165
+ protected boolean isSupportedConverter (ConverterRegistrationIntent registrationIntent ) {
133
166
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 ());
136
170
137
171
if (LOG .isDebugEnabled ()) {
138
172
139
173
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" ));
143
177
} 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 ()));
147
181
}
148
182
}
149
183
@@ -285,6 +319,17 @@ private Object register(ConverterRegistration converterRegistration) {
285
319
return converterRegistration .getConverter ();
286
320
}
287
321
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
+
288
333
/**
289
334
* Returns the target type to convert to in case we have a custom conversion registered to convert the given source
290
335
* type into a Mongo native one.
@@ -765,4 +810,42 @@ private boolean isStoreSimpleType(Class<?> type) {
765
810
return storeTypeHolder .isSimpleType (type );
766
811
}
767
812
}
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
+ }
768
851
}
0 commit comments