66import java .util .Collections ;
77import java .util .Date ;
88import java .util .List ;
9+ import java .util .function .Consumer ;
910
11+ import org .springframework .core .convert .converter .Converter ;
12+ import org .springframework .core .convert .converter .ConverterFactory ;
13+ import org .springframework .core .convert .converter .GenericConverter ;
14+ import org .springframework .data .convert .ConverterBuilder ;
1015import org .springframework .data .convert .CustomConversions ;
1116import org .springframework .data .r2dbc .dialect .R2dbcDialect ;
1217import org .springframework .data .r2dbc .mapping .R2dbcSimpleTypeHolder ;
18+ import org .springframework .data .relational .core .dialect .Dialect ;
19+ import org .springframework .lang .Contract ;
20+ import org .springframework .util .Assert ;
1321
1422/**
1523 * Value object to capture custom conversion. {@link R2dbcCustomConversions} also act as factory for
@@ -70,11 +78,27 @@ public static R2dbcCustomConversions of(R2dbcDialect dialect, Object... converte
7078 * @since 1.2
7179 */
7280 public static R2dbcCustomConversions of (R2dbcDialect dialect , Collection <?> converters ) {
81+ return create (dialect , configurer -> configurer .registerConverters (converters ));
82+ }
83+
84+ /**
85+ * Create a new {@link R2dbcCustomConversions} instance using the given {@link R2dbcDialect} and
86+ * {@link R2dbcConverterConfigurer} callback to configure converters.
87+ *
88+ * @param dialect the {@link Dialect} to use, must not be {@literal null}.
89+ * @param configurer the configurer callback to configure converters, must not be {@literal null}.
90+ * @return a new {@link R2dbcCustomConversions} instance configured from the given dialect and configured converters.
91+ * @since 4.0
92+ */
93+ public static R2dbcCustomConversions create (R2dbcDialect dialect , Consumer <R2dbcConverterConfigurer > configurer ) {
7394
74- List < Object > storeConverters = new ArrayList <>( dialect . getConverters () );
75- storeConverters . addAll ( R2dbcCustomConversions . STORE_CONVERTERS );
95+ Assert . notNull ( dialect , "Dialect must not be null" );
96+ Assert . notNull ( configurer , "R2dbcConverterConfigurer Consumer must not be null" );
7697
77- return new R2dbcCustomConversions (StoreConversions .of (dialect .getSimpleTypeHolder (), storeConverters ), converters );
98+ R2dbcConverterConfigurer converterConfigurer = R2dbcConverterConfigurer .from (dialect );
99+ configurer .accept (converterConfigurer );
100+
101+ return new R2dbcCustomConversions (converterConfigurer .createConfiguration ());
78102 }
79103
80104 static class R2dbcCustomConversionsConfiguration extends ConverterConfiguration {
@@ -92,4 +116,112 @@ public R2dbcCustomConversionsConfiguration(StoreConversions storeConversions, Li
92116 });
93117 }
94118 }
119+
120+ /**
121+ * {@link R2dbcConverterConfigurer} encapsulates creation of {@link R2dbcCustomConversionsConfiguration} with R2DBC
122+ * specifics.
123+ *
124+ * @author Mark Paluch
125+ * @since 4.0
126+ */
127+ public static class R2dbcConverterConfigurer {
128+
129+ private final StoreConversions storeConversions ;
130+ private final List <Object > customConverters = new ArrayList <>();
131+
132+ private R2dbcConverterConfigurer (StoreConversions storeConversions ) {
133+ this .storeConversions = storeConversions ;
134+ }
135+
136+ /**
137+ * Create a {@link R2dbcConverterConfigurer} using the provided {@code dialect} and our own codecs for JSR-310
138+ * types.
139+ *
140+ * @param dialect must not be {@literal null}.
141+ * @return
142+ */
143+ static R2dbcConverterConfigurer from (R2dbcDialect dialect ) {
144+
145+ List <Object > converters = new ArrayList <>();
146+ converters .addAll (dialect .getConverters ());
147+ converters .addAll (R2dbcCustomConversions .STORE_CONVERTERS );
148+
149+ StoreConversions storeConversions = StoreConversions .of (dialect .getSimpleTypeHolder (), converters );
150+
151+ return new R2dbcConverterConfigurer (storeConversions );
152+ }
153+
154+ /**
155+ * Create a {@link R2dbcConverterConfigurer} using the provided {@code storeConversions}.
156+ *
157+ * @param storeConversions must not be {@literal null}.
158+ * @return
159+ */
160+ static R2dbcConverterConfigurer from (StoreConversions storeConversions ) {
161+ return new R2dbcConverterConfigurer (storeConversions );
162+ }
163+
164+ /**
165+ * Add a custom {@link Converter} implementation.
166+ *
167+ * @param converter must not be {@literal null}.
168+ * @return this.
169+ */
170+ @ Contract ("_ -> this" )
171+ public R2dbcConverterConfigurer registerConverter (Converter <?, ?> converter ) {
172+
173+ Assert .notNull (converter , "Converter must not be null" );
174+ customConverters .add (converter );
175+ return this ;
176+ }
177+
178+ /**
179+ * Add {@link Converter converters}, {@link ConverterFactory factories}, {@link ConverterBuilder.ConverterAware
180+ * converter-aware objects}, and {@link GenericConverter generic converters}.
181+ *
182+ * @param converters must not be {@literal null} nor contain {@literal null} values.
183+ * @return this.
184+ */
185+ @ Contract ("_ -> this" )
186+ public R2dbcConverterConfigurer registerConverters (Object ... converters ) {
187+ return registerConverters (Arrays .asList (converters ));
188+ }
189+
190+ /**
191+ * Add {@link Converter converters}, {@link ConverterFactory factories}, {@link ConverterBuilder.ConverterAware
192+ * converter-aware objects}, and {@link GenericConverter generic converters}.
193+ *
194+ * @param converters must not be {@literal null} nor contain {@literal null} values.
195+ * @return this.
196+ */
197+ @ Contract ("_ -> this" )
198+ public R2dbcConverterConfigurer registerConverters (Collection <?> converters ) {
199+
200+ Assert .notNull (converters , "Converters must not be null" );
201+ Assert .noNullElements (converters , "Converters must not be null nor contain null values" );
202+
203+ customConverters .addAll (converters );
204+ return this ;
205+ }
206+
207+ /**
208+ * Add a custom {@link ConverterFactory} implementation.
209+ *
210+ * @param converterFactory must not be {@literal null}.
211+ * @return this.
212+ */
213+ @ Contract ("_ -> this" )
214+ public R2dbcConverterConfigurer registerConverterFactory (ConverterFactory <?, ?> converterFactory ) {
215+
216+ Assert .notNull (converterFactory , "ConverterFactory must not be null" );
217+ customConverters .add (converterFactory );
218+ return this ;
219+ }
220+
221+ ConverterConfiguration createConfiguration () {
222+ return new R2dbcCustomConversionsConfiguration (storeConversions , this .customConverters );
223+ }
224+
225+ }
226+
95227}
0 commit comments