20
20
21
21
import java .util .ArrayList ;
22
22
import java .util .List ;
23
+ import java .util .Map ;
24
+ import java .util .Optional ;
25
+ import java .util .concurrent .ConcurrentHashMap ;
26
+
27
+ import org .reactivestreams .Publisher ;
23
28
24
29
import org .springframework .data .repository .util .ReactiveWrapperConverters ;
25
30
import org .springframework .data .repository .util .ReactiveWrappers ;
26
31
27
32
/**
28
33
* Reactive {@link org.springframework.data.repository.query.ParametersParameterAccessor} implementation that subscribes
29
- * to reactive parameter wrapper types upon creation. This class performs synchronization when acessing parameters.
34
+ * to reactive parameter wrapper types upon creation. This class performs synchronization when accessing parameters.
30
35
*
31
36
* @author Mark Paluch
32
37
* @author Christoph Strobl
33
38
* @since 2.0
34
39
*/
35
40
class ReactiveMongoParameterAccessor extends MongoParametersParameterAccessor {
36
41
37
- private final List < Mono <?>> subscriptions ;
42
+ private final Object [] values ;
38
43
39
44
public ReactiveMongoParameterAccessor (MongoQueryMethod method , Object [] values ) {
40
45
41
46
super (method , values );
47
+ this .values = values ;
42
48
43
- this .subscriptions = new ArrayList <>(values .length );
44
-
45
- for (int i = 0 ; i < values .length ; i ++) {
46
-
47
- Object value = values [i ];
48
-
49
- if (value == null || !ReactiveWrappers .supports (value .getClass ())) {
50
- subscriptions .add (null );
51
- continue ;
52
- }
53
-
54
- if (ReactiveWrappers .isSingleValueType (value .getClass ())) {
55
- subscriptions .add (ReactiveWrapperConverters .toWrapper (value , Mono .class ).share ());
56
- } else {
57
- subscriptions .add (ReactiveWrapperConverters .toWrapper (value , Flux .class ).collectList ().share ());
58
- }
59
- }
60
- }
61
-
62
- /* (non-Javadoc)
63
- * @see org.springframework.data.repository.query.ParametersParameterAccessor#getValue(int)
64
- */
65
- @ SuppressWarnings ("unchecked" )
66
- @ Override
67
- protected <T > T getValue (int index ) {
68
-
69
- if (subscriptions .get (index ) != null ) {
70
- return (T ) subscriptions .get (index ).block ();
71
- }
72
-
73
- return super .getValue (index );
74
49
}
75
50
76
51
/* (non-Javadoc)
@@ -86,10 +61,64 @@ public Object[] getValues() {
86
61
return result ;
87
62
}
88
63
89
- /* (non-Javadoc)
90
- * @see org.springframework.data.repository.query.ParametersParameterAccessor#getBindableValue(int)
91
- */
92
64
public Object getBindableValue (int index ) {
93
65
return getValue (getParameters ().getBindableParameter (index ).getIndex ());
94
66
}
67
+
68
+ /**
69
+ * Resolve parameters that were provided through reactive wrapper types. Flux is collected into a list, values from
70
+ * Mono's are used directly.
71
+ *
72
+ * @return
73
+ */
74
+ @ SuppressWarnings ("unchecked" )
75
+ public Mono <ReactiveMongoParameterAccessor > resolveParameters () {
76
+
77
+ boolean hasReactiveWrapper = false ;
78
+
79
+ for (Object value : values ) {
80
+ if (value == null || !ReactiveWrappers .supports (value .getClass ())) {
81
+ continue ;
82
+ }
83
+
84
+ hasReactiveWrapper = true ;
85
+ break ;
86
+ }
87
+
88
+ if (!hasReactiveWrapper ) {
89
+ return Mono .just (this );
90
+ }
91
+
92
+ Object [] resolved = new Object [values .length ];
93
+ Map <Integer , Optional <?>> holder = new ConcurrentHashMap <>();
94
+ List <Publisher <?>> publishers = new ArrayList <>();
95
+
96
+ for (int i = 0 ; i < values .length ; i ++) {
97
+
98
+ Object value = resolved [i ] = values [i ];
99
+ if (value == null || !ReactiveWrappers .supports (value .getClass ())) {
100
+ continue ;
101
+ }
102
+
103
+ if (ReactiveWrappers .isSingleValueType (value .getClass ())) {
104
+
105
+ int index = i ;
106
+ publishers .add (ReactiveWrapperConverters .toWrapper (value , Mono .class ) //
107
+ .map (Optional ::of ) //
108
+ .defaultIfEmpty (Optional .empty ()) //
109
+ .doOnNext (it -> holder .put (index , (Optional <?>) it )));
110
+ } else {
111
+
112
+ int index = i ;
113
+ publishers .add (ReactiveWrapperConverters .toWrapper (value , Flux .class ) //
114
+ .collectList () //
115
+ .doOnNext (it -> holder .put (index , Optional .of (it ))));
116
+ }
117
+ }
118
+
119
+ return Flux .merge (publishers ).then ().thenReturn (resolved ).map (values -> {
120
+ holder .forEach ((index , v ) -> values [index ] = v .orElse (null ));
121
+ return new ReactiveMongoParameterAccessor (method , values );
122
+ });
123
+ }
95
124
}
0 commit comments