18
18
import io .reactivex .Flowable ;
19
19
import io .reactivex .Maybe ;
20
20
import kotlinx .coroutines .flow .Flow ;
21
+ import kotlinx .coroutines .flow .FlowKt ;
21
22
import kotlinx .coroutines .reactive .ReactiveFlowKt ;
22
23
import reactor .core .publisher .Flux ;
23
24
import reactor .core .publisher .Mono ;
26
27
27
28
import java .util .ArrayList ;
28
29
import java .util .List ;
30
+ import java .util .function .Consumer ;
29
31
import java .util .function .Function ;
30
32
31
33
import javax .annotation .Nonnull ;
@@ -97,6 +99,10 @@ public abstract class ReactiveWrapperConverters {
97
99
REACTIVE_WRAPPERS .add (PublisherWrapper .INSTANCE );
98
100
}
99
101
102
+ if (ReactiveWrappers .isAvailable (ReactiveLibrary .KOTLIN_COROUTINES )) {
103
+ REACTIVE_WRAPPERS .add (FlowWrapper .INSTANCE );
104
+ }
105
+
100
106
registerConvertersIn (GENERIC_CONVERSION_SERVICE );
101
107
}
102
108
@@ -184,6 +190,50 @@ public static <T> T map(Object reactiveObject, Function<Object, Object> converte
184
190
.orElseThrow (() -> new IllegalStateException (String .format ("Cannot apply converter to %s" , reactiveObject )));
185
191
}
186
192
193
+ /**
194
+ * Apply a {@link Runnable} when the reactive type emits a completion signal.
195
+ *
196
+ * @param reactiveObject must not be {@literal null}.
197
+ * @param onSuccess must not be {@literal null}.
198
+ * @return
199
+ * @since 2.4
200
+ */
201
+ @ SuppressWarnings ("unchecked" )
202
+ public static <T > T doOnSuccess (Object reactiveObject , Runnable onSuccess ) {
203
+
204
+ Assert .notNull (reactiveObject , "Reactive source object must not be null!" );
205
+ Assert .notNull (onSuccess , "onSuccess callback must not be null!" );
206
+
207
+ return REACTIVE_WRAPPERS .stream ()//
208
+ .filter (it -> ClassUtils .isAssignable (it .getWrapperClass (), reactiveObject .getClass ()))//
209
+ .findFirst ()//
210
+ .map (it -> (T ) it .doOnSuccess (reactiveObject , onSuccess ))//
211
+ .orElseThrow (
212
+ () -> new IllegalStateException (String .format ("Cannot apply onSuccess callback to %s" , reactiveObject )));
213
+ }
214
+
215
+ /**
216
+ * Apply a {@link Consumer} when the reactive type emits an error signal.
217
+ *
218
+ * @param reactiveObject must not be {@literal null}.
219
+ * @param onError must not be {@literal null}.
220
+ * @return
221
+ * @since 2.4
222
+ */
223
+ @ SuppressWarnings ("unchecked" )
224
+ public static <T > T doOnError (Object reactiveObject , Consumer <? super Throwable > onError ) {
225
+
226
+ Assert .notNull (reactiveObject , "Reactive source object must not be null!" );
227
+ Assert .notNull (onError , "onError callback must not be null!" );
228
+
229
+ return REACTIVE_WRAPPERS .stream ()//
230
+ .filter (it -> ClassUtils .isAssignable (it .getWrapperClass (), reactiveObject .getClass ()))//
231
+ .findFirst ()//
232
+ .map (it -> (T ) it .doOnError (reactiveObject , onError ))//
233
+ .orElseThrow (
234
+ () -> new IllegalStateException (String .format ("Cannot apply onError callback to %s" , reactiveObject )));
235
+ }
236
+
187
237
/**
188
238
* Return {@literal true} if objects of {@code sourceType} can be converted to the {@code targetType}.
189
239
*
@@ -209,7 +259,7 @@ public static boolean canConvert(Class<?> sourceType, Class<?> targetType) {
209
259
* @author Mark Paluch
210
260
* @author Christoph Strobl
211
261
*/
212
- private static interface ReactiveTypeWrapper <T > {
262
+ private interface ReactiveTypeWrapper <T > {
213
263
214
264
/**
215
265
* @return the wrapper class.
@@ -224,6 +274,26 @@ private static interface ReactiveTypeWrapper<T> {
224
274
* @return the reactive type applying conversion.
225
275
*/
226
276
Object map (Object wrapper , Function <Object , Object > function );
277
+
278
+ /**
279
+ * Apply a {@link Runnable} when the reactive type emits a completion signal.
280
+ *
281
+ * @param wrapper the reactive type, must not be {@literal null}.
282
+ * @param onSuccess the signal callback, must not be {@literal null}.
283
+ * @return the reactive type with {@code onSuccess} attached.
284
+ * @since 2.4
285
+ */
286
+ Object doOnSuccess (Object wrapper , Runnable onSuccess );
287
+
288
+ /**
289
+ * Apply a {@link Consumer} when the reactive type emits an error signal.
290
+ *
291
+ * @param wrapper the reactive type, must not be {@literal null}.
292
+ * @param onError the error consumer, must not be {@literal null}.
293
+ * @return the reactive type with {@code onError} attached.
294
+ * @since 2.4
295
+ */
296
+ Object doOnError (Object wrapper , Consumer <? super Throwable > onError );
227
297
}
228
298
229
299
/**
@@ -242,6 +312,16 @@ public Class<? super Mono<?>> getWrapperClass() {
242
312
public Mono <?> map (Object wrapper , Function <Object , Object > function ) {
243
313
return ((Mono <?>) wrapper ).map (function ::apply );
244
314
}
315
+
316
+ @ Override
317
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
318
+ return ((Mono <?>) wrapper ).doOnSuccess (o -> onSuccess .run ());
319
+ }
320
+
321
+ @ Override
322
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
323
+ return ((Mono <?>) wrapper ).doOnError (onError );
324
+ }
245
325
}
246
326
247
327
/**
@@ -257,7 +337,56 @@ public Class<? super Flux<?>> getWrapperClass() {
257
337
}
258
338
259
339
public Flux <?> map (Object wrapper , Function <Object , Object > function ) {
260
- return ((Flux <?>) wrapper ).map (function ::apply );
340
+ return ((Flux <?>) wrapper ).map (function );
341
+ }
342
+
343
+ @ Override
344
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
345
+ return ((Flux <?>) wrapper ).doOnComplete (onSuccess );
346
+ }
347
+
348
+ @ Override
349
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
350
+ return ((Flux <?>) wrapper ).doOnError (onError );
351
+ }
352
+ }
353
+
354
+ /**
355
+ * Wrapper for Kotlin's {@link Flow}.
356
+ *
357
+ * @since 2.4
358
+ */
359
+ private enum FlowWrapper implements ReactiveTypeWrapper <Flow <?>> {
360
+
361
+ INSTANCE ;
362
+
363
+ @ Override
364
+ public Class <? super Flow <?>> getWrapperClass () {
365
+ return Flow .class ;
366
+ }
367
+
368
+ public Flow <?> map (Object wrapper , Function <Object , Object > function ) {
369
+ return FlowKt .map ((Flow <?>) wrapper , (o , continuation ) -> function .apply (o ));
370
+ }
371
+
372
+ @ Override
373
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
374
+ return FlowKt .onCompletion ((Flow <?>) wrapper , (collector , ex , continuation ) -> {
375
+ if (ex == null ) {
376
+ onSuccess .run ();
377
+ }
378
+ return collector ;
379
+ });
380
+ }
381
+
382
+ @ Override
383
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
384
+ return FlowKt .onCompletion ((Flow <?>) wrapper , (collector , ex , continuation ) -> {
385
+ if (ex != null ) {
386
+ onError .accept (ex );
387
+ }
388
+ return collector ;
389
+ });
261
390
}
262
391
}
263
392
@@ -286,6 +415,34 @@ public Publisher<?> map(Object wrapper, Function<Object, Object> function) {
286
415
287
416
return FluxWrapper .INSTANCE .map (Flux .from ((Publisher <?>) wrapper ), function );
288
417
}
418
+
419
+ @ Override
420
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
421
+
422
+ if (wrapper instanceof Mono ) {
423
+ return MonoWrapper .INSTANCE .doOnSuccess (wrapper , onSuccess );
424
+ }
425
+
426
+ if (wrapper instanceof Flux ) {
427
+ return FluxWrapper .INSTANCE .doOnSuccess (wrapper , onSuccess );
428
+ }
429
+
430
+ return FluxWrapper .INSTANCE .doOnSuccess (Flux .from ((Publisher <?>) wrapper ), onSuccess );
431
+ }
432
+
433
+ @ Override
434
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
435
+
436
+ if (wrapper instanceof Mono ) {
437
+ return MonoWrapper .INSTANCE .doOnError (wrapper , onError );
438
+ }
439
+
440
+ if (wrapper instanceof Flux ) {
441
+ return FluxWrapper .INSTANCE .doOnError (wrapper , onError );
442
+ }
443
+
444
+ return FluxWrapper .INSTANCE .doOnError (Flux .from ((Publisher <?>) wrapper ), onError );
445
+ }
289
446
}
290
447
291
448
// -------------------------------------------------------------------------
@@ -308,6 +465,16 @@ public Class<? super Single<?>> getWrapperClass() {
308
465
public Single <?> map (Object wrapper , Function <Object , Object > function ) {
309
466
return ((Single <?>) wrapper ).map (function ::apply );
310
467
}
468
+
469
+ @ Override
470
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
471
+ return ((Single <?>) wrapper ).doOnSuccess (o -> onSuccess .run ());
472
+ }
473
+
474
+ @ Override
475
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
476
+ return ((Single <?>) wrapper ).doOnError (onError ::accept );
477
+ }
311
478
}
312
479
313
480
/**
@@ -326,6 +493,16 @@ public Class<? super Observable<?>> getWrapperClass() {
326
493
public Observable <?> map (Object wrapper , Function <Object , Object > function ) {
327
494
return ((Observable <?>) wrapper ).map (function ::apply );
328
495
}
496
+
497
+ @ Override
498
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
499
+ return ((Observable <?>) wrapper ).doOnCompleted (onSuccess ::run );
500
+ }
501
+
502
+ @ Override
503
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
504
+ return ((Observable <?>) wrapper ).doOnError (onError ::accept );
505
+ }
329
506
}
330
507
331
508
// -------------------------------------------------------------------------
@@ -348,6 +525,16 @@ public Class<? super io.reactivex.Single<?>> getWrapperClass() {
348
525
public io .reactivex .Single <?> map (Object wrapper , Function <Object , Object > function ) {
349
526
return ((io .reactivex .Single <?>) wrapper ).map (function ::apply );
350
527
}
528
+
529
+ @ Override
530
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
531
+ return ((io .reactivex .Single <?>) wrapper ).doOnSuccess (o -> onSuccess .run ());
532
+ }
533
+
534
+ @ Override
535
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
536
+ return ((io .reactivex .Single <?>) wrapper ).doOnError (onError ::accept );
537
+ }
351
538
}
352
539
353
540
/**
@@ -366,6 +553,16 @@ public Class<? super io.reactivex.Maybe<?>> getWrapperClass() {
366
553
public io .reactivex .Maybe <?> map (Object wrapper , Function <Object , Object > function ) {
367
554
return ((io .reactivex .Maybe <?>) wrapper ).map (function ::apply );
368
555
}
556
+
557
+ @ Override
558
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
559
+ return ((io .reactivex .Maybe <?>) wrapper ).doOnSuccess (o -> onSuccess .run ());
560
+ }
561
+
562
+ @ Override
563
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
564
+ return ((io .reactivex .Maybe <?>) wrapper ).doOnError (onError ::accept );
565
+ }
369
566
}
370
567
371
568
/**
@@ -384,6 +581,16 @@ public Class<? super io.reactivex.Observable<?>> getWrapperClass() {
384
581
public io .reactivex .Observable <?> map (Object wrapper , Function <Object , Object > function ) {
385
582
return ((io .reactivex .Observable <?>) wrapper ).map (function ::apply );
386
583
}
584
+
585
+ @ Override
586
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
587
+ return ((io .reactivex .Observable <?>) wrapper ).doOnComplete (onSuccess ::run );
588
+ }
589
+
590
+ @ Override
591
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
592
+ return ((io .reactivex .Observable <?>) wrapper ).doOnError (onError ::accept );
593
+ }
387
594
}
388
595
389
596
/**
@@ -402,6 +609,16 @@ public Class<? super Flowable<?>> getWrapperClass() {
402
609
public io .reactivex .Flowable <?> map (Object wrapper , Function <Object , Object > function ) {
403
610
return ((io .reactivex .Flowable <?>) wrapper ).map (function ::apply );
404
611
}
612
+
613
+ @ Override
614
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
615
+ return ((io .reactivex .Flowable <?>) wrapper ).doOnComplete (onSuccess ::run );
616
+ }
617
+
618
+ @ Override
619
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
620
+ return ((io .reactivex .Flowable <?>) wrapper ).doOnError (onError ::accept );
621
+ }
405
622
}
406
623
407
624
// -------------------------------------------------------------------------
@@ -424,6 +641,16 @@ public Class<? super io.reactivex.rxjava3.core.Single<?>> getWrapperClass() {
424
641
public io .reactivex .rxjava3 .core .Single <?> map (Object wrapper , Function <Object , Object > function ) {
425
642
return ((io .reactivex .rxjava3 .core .Single <?>) wrapper ).map (function ::apply );
426
643
}
644
+
645
+ @ Override
646
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
647
+ return ((io .reactivex .rxjava3 .core .Single <?>) wrapper ).doOnSuccess (o -> onSuccess .run ());
648
+ }
649
+
650
+ @ Override
651
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
652
+ return ((io .reactivex .rxjava3 .core .Single <?>) wrapper ).doOnError (onError ::accept );
653
+ }
427
654
}
428
655
429
656
/**
@@ -442,6 +669,16 @@ public Class<? super io.reactivex.rxjava3.core.Maybe<?>> getWrapperClass() {
442
669
public io .reactivex .rxjava3 .core .Maybe <?> map (Object wrapper , Function <Object , Object > function ) {
443
670
return ((io .reactivex .rxjava3 .core .Maybe <?>) wrapper ).map (function ::apply );
444
671
}
672
+
673
+ @ Override
674
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
675
+ return ((io .reactivex .rxjava3 .core .Maybe <?>) wrapper ).doOnSuccess (o -> onSuccess .run ());
676
+ }
677
+
678
+ @ Override
679
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
680
+ return ((io .reactivex .rxjava3 .core .Maybe <?>) wrapper ).doOnError (onError ::accept );
681
+ }
445
682
}
446
683
447
684
/**
@@ -460,6 +697,16 @@ public Class<? super io.reactivex.rxjava3.core.Observable<?>> getWrapperClass()
460
697
public io .reactivex .rxjava3 .core .Observable <?> map (Object wrapper , Function <Object , Object > function ) {
461
698
return ((io .reactivex .rxjava3 .core .Observable <?>) wrapper ).map (function ::apply );
462
699
}
700
+
701
+ @ Override
702
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
703
+ return ((io .reactivex .rxjava3 .core .Observable <?>) wrapper ).doOnComplete (onSuccess ::run );
704
+ }
705
+
706
+ @ Override
707
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
708
+ return ((io .reactivex .rxjava3 .core .Observable <?>) wrapper ).doOnError (onError ::accept );
709
+ }
463
710
}
464
711
465
712
/**
@@ -478,6 +725,16 @@ public Class<? super io.reactivex.rxjava3.core.Flowable<?>> getWrapperClass() {
478
725
public io .reactivex .rxjava3 .core .Flowable <?> map (Object wrapper , Function <Object , Object > function ) {
479
726
return ((io .reactivex .rxjava3 .core .Flowable <?>) wrapper ).map (function ::apply );
480
727
}
728
+
729
+ @ Override
730
+ public Object doOnSuccess (Object wrapper , Runnable onSuccess ) {
731
+ return ((io .reactivex .rxjava3 .core .Flowable <?>) wrapper ).doOnComplete (onSuccess ::run );
732
+ }
733
+
734
+ @ Override
735
+ public Object doOnError (Object wrapper , Consumer <? super Throwable > onError ) {
736
+ return ((io .reactivex .rxjava3 .core .Flowable <?>) wrapper ).doOnError (onError ::accept );
737
+ }
481
738
}
482
739
483
740
// -------------------------------------------------------------------------
0 commit comments