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