15
15
*/
16
16
package org .springframework .data .repository .init ;
17
17
18
+ import reactor .core .publisher .Flux ;
19
+ import reactor .core .publisher .Mono ;
20
+
18
21
import java .io .IOException ;
22
+ import java .lang .reflect .Method ;
19
23
import java .util .Arrays ;
20
24
import java .util .Collection ;
21
25
import java .util .Collections ;
26
+ import java .util .HashMap ;
27
+ import java .util .Map ;
22
28
23
29
import org .apache .commons .logging .Log ;
24
30
import org .apache .commons .logging .LogFactory ;
31
+ import org .reactivestreams .Publisher ;
32
+
25
33
import org .springframework .context .ApplicationEventPublisher ;
26
34
import org .springframework .context .ApplicationEventPublisherAware ;
27
35
import org .springframework .core .io .Resource ;
28
36
import org .springframework .core .io .support .PathMatchingResourcePatternResolver ;
29
37
import org .springframework .core .io .support .ResourcePatternResolver ;
30
- import org .springframework .data .repository .support .DefaultRepositoryInvokerFactory ;
38
+ import org .springframework .data .repository .CrudRepository ;
39
+ import org .springframework .data .repository .core .CrudMethods ;
40
+ import org .springframework .data .repository .core .RepositoryInformation ;
41
+ import org .springframework .data .repository .core .RepositoryMetadata ;
42
+ import org .springframework .data .repository .core .support .DefaultCrudMethods ;
43
+ import org .springframework .data .repository .reactive .ReactiveCrudRepository ;
31
44
import org .springframework .data .repository .support .Repositories ;
32
- import org .springframework .data .repository .support .RepositoryInvoker ;
33
- import org .springframework .data .repository .support .RepositoryInvokerFactory ;
45
+ import org .springframework .data .repository .util .ReactiveWrapperConverters ;
34
46
import org .springframework .lang .Nullable ;
35
47
import org .springframework .util .Assert ;
48
+ import org .springframework .util .ReflectionUtils ;
36
49
37
50
/**
38
51
* A {@link RepositoryPopulator} using a {@link ResourceReader} to read objects from the configured {@link Resource}s.
39
52
*
40
53
* @author Oliver Gierke
41
54
* @author Christoph Strobl
55
+ * @author Mark Paluch
42
56
* @since 1.4
43
57
*/
44
58
public class ResourceReaderRepositoryPopulator implements RepositoryPopulator , ApplicationEventPublisherAware {
45
59
46
- private static final Log logger = LogFactory .getLog (ResourceReaderRepositoryPopulator .class );
60
+ private static final Log logger = LogFactory .getLog (ResourceReaderRepositoryPopulator .class );
47
61
48
62
private final ResourceReader reader ;
49
63
private final @ Nullable ClassLoader classLoader ;
@@ -114,7 +128,7 @@ public void populate(Repositories repositories) {
114
128
115
129
Assert .notNull (repositories , "Repositories must not be null!" );
116
130
117
- RepositoryInvokerFactory invokerFactory = new DefaultRepositoryInvokerFactory (repositories );
131
+ RepositoryPersisterFactory persisterFactory = new RepositoryPersisterFactory (repositories );
118
132
119
133
for (Resource resource : resources ) {
120
134
@@ -125,13 +139,13 @@ public void populate(Repositories repositories) {
125
139
if (result instanceof Collection ) {
126
140
for (Object element : (Collection <?>) result ) {
127
141
if (element != null ) {
128
- persist (element , invokerFactory );
142
+ persist (element , persisterFactory );
129
143
} else {
130
144
logger .info ("Skipping null element found in unmarshal result!" );
131
145
}
132
146
}
133
147
} else {
134
- persist (result , invokerFactory );
148
+ persist (result , persisterFactory );
135
149
}
136
150
}
137
151
@@ -158,12 +172,172 @@ private Object readObjectFrom(Resource resource) {
158
172
* Persists the given {@link Object} using a suitable repository.
159
173
*
160
174
* @param object must not be {@literal null}.
161
- * @param invokerFactory must not be {@literal null}.
175
+ * @param persisterFactory must not be {@literal null}.
176
+ */
177
+ private void persist (Object object , RepositoryPersisterFactory persisterFactory ) {
178
+
179
+ RepositoryPersister persister = persisterFactory .getPersisterFor (object .getClass ());
180
+ logger .debug (String .format ("Persisting %s using repository %s" , object , persister ));
181
+ persister .save (object );
182
+ }
183
+
184
+ /**
185
+ * Factory to create {@link RepositoryPersister} instances.
186
+ */
187
+ static class RepositoryPersisterFactory {
188
+
189
+ private final Map <Class <?>, RepositoryPersister > persisters = new HashMap <>();
190
+ private final Repositories repositories ;
191
+
192
+ public RepositoryPersisterFactory (Repositories repositories ) {
193
+ this .repositories = repositories ;
194
+ }
195
+
196
+ /**
197
+ * Obtain a {@link RepositoryPersister}.
198
+ *
199
+ * @param domainType
200
+ * @return
201
+ */
202
+ public RepositoryPersister getPersisterFor (Class <?> domainType ) {
203
+ return persisters .computeIfAbsent (domainType , this ::createPersisterFor );
204
+ }
205
+
206
+ private RepositoryPersister createPersisterFor (Class <?> domainType ) {
207
+
208
+ RepositoryInformation repositoryInformation = repositories .getRequiredRepositoryInformation (domainType );
209
+ Object repository = repositories .getRepositoryFor (domainType ).orElseThrow (
210
+ () -> new IllegalArgumentException (String .format ("No repository found for domain type: %s" , domainType )));
211
+
212
+ if (repositoryInformation .isReactiveRepository ()) {
213
+ return repository instanceof ReactiveCrudRepository ? new ReactiveCrudRepositoryPersister (repository )
214
+ : new ReflectiveReactivePersister (repositoryInformation , repository );
215
+ }
216
+
217
+ if (repository instanceof CrudRepository ) {
218
+ return new CrudRepositoryPersister (repository );
219
+ }
220
+
221
+ return new ReflectivePersister (repositoryInformation , repository );
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Interface defining a save method to persist an object within a repository.
227
+ */
228
+ interface RepositoryPersister {
229
+
230
+ /**
231
+ * Saves the {@code object} in an appropriate repository.
232
+ *
233
+ * @param object
234
+ */
235
+ void save (Object object );
236
+ }
237
+
238
+ /**
239
+ * Reflection variant of a {@link RepositoryPersister}.
240
+ */
241
+ private static class ReflectivePersister implements RepositoryPersister {
242
+
243
+ private final CrudMethods methods ;
244
+ private final Object repository ;
245
+
246
+ public ReflectivePersister (RepositoryMetadata metadata , Object repository ) {
247
+ this .methods = new DefaultCrudMethods (metadata );
248
+ this .repository = repository ;
249
+ }
250
+
251
+ @ Override
252
+ public void save (Object object ) {
253
+
254
+ doPersist (object );
255
+ }
256
+
257
+ Object doPersist (Object object ) {
258
+ Method method = methods .getSaveMethod ()//
259
+ .orElseThrow (() -> new IllegalStateException ("Repository doesn't have a save-method declared!" ));
260
+
261
+ return ReflectionUtils .invokeMethod (method , repository , object );
262
+ }
263
+
264
+ @ Override
265
+ public String toString () {
266
+ return repository .toString ();
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Reactive extension to save objects in a reactive repository.
272
+ */
273
+ private static class ReflectiveReactivePersister extends ReflectivePersister {
274
+
275
+ public ReflectiveReactivePersister (RepositoryMetadata metadata , Object repository ) {
276
+ super (metadata , repository );
277
+ }
278
+
279
+ @ Override
280
+ public void save (Object object ) {
281
+
282
+ Object wrapper = doPersist (object );
283
+
284
+ Publisher <?> publisher = ReactiveWrapperConverters .toWrapper (wrapper , Publisher .class );
285
+
286
+ if (!(publisher instanceof Mono )) {
287
+ publisher = Flux .from (publisher ).collectList ();
288
+ }
289
+
290
+ Mono .from (publisher ).block ();
291
+ }
292
+ }
293
+
294
+ /**
295
+ * {@link RepositoryPersister} to operate with {@link CrudRepository}.
162
296
*/
163
- private void persist ( Object object , RepositoryInvokerFactory invokerFactory ) {
297
+ private static class CrudRepositoryPersister implements RepositoryPersister {
164
298
165
- RepositoryInvoker invoker = invokerFactory .getInvokerFor (object .getClass ());
166
- logger .debug (String .format ("Persisting %s using repository %s" , object , invoker ));
167
- invoker .invokeSave (object );
299
+ private final CrudRepository <Object , Object > repository ;
300
+
301
+ @ SuppressWarnings ("unchecked" )
302
+ public CrudRepositoryPersister (Object repository ) {
303
+
304
+ Assert .isInstanceOf (CrudRepository .class , repository );
305
+ this .repository = (CrudRepository <Object , Object >) repository ;
306
+ }
307
+
308
+ @ Override
309
+ public void save (Object object ) {
310
+ repository .save (object );
311
+ }
312
+
313
+ @ Override
314
+ public String toString () {
315
+ return repository .toString ();
316
+ }
317
+ }
318
+
319
+ /**
320
+ * {@link RepositoryPersister} to operate with {@link ReactiveCrudRepository}.
321
+ */
322
+ private static class ReactiveCrudRepositoryPersister implements RepositoryPersister {
323
+
324
+ private final ReactiveCrudRepository <Object , Object > repository ;
325
+
326
+ @ SuppressWarnings ("unchecked" )
327
+ public ReactiveCrudRepositoryPersister (Object repository ) {
328
+
329
+ Assert .isInstanceOf (ReactiveCrudRepository .class , repository );
330
+ this .repository = (ReactiveCrudRepository <Object , Object >) repository ;
331
+ }
332
+
333
+ @ Override
334
+ public void save (Object object ) {
335
+ repository .save (object ).block ();
336
+ }
337
+
338
+ @ Override
339
+ public String toString () {
340
+ return repository .toString ();
341
+ }
168
342
}
169
343
}
0 commit comments