@@ -112,6 +112,35 @@ public static Publisher<?> invokeSuspendingFunction(Method method, Object target
112
112
@ SuppressWarnings ({"DataFlowIssue" , "NullAway" })
113
113
public static Publisher <?> invokeSuspendingFunction (
114
114
CoroutineContext context , Method method , @ Nullable Object target , @ Nullable Object ... args ) {
115
+ return invokeSuspendingFunctionCore (context , method , target , args , false );
116
+ }
117
+
118
+ /**
119
+ * Invoke a suspending function and convert it to {@link Mono} or
120
+ * {@link Flux}.
121
+ * @param context the coroutine context to use
122
+ * @param method the suspending function to invoke
123
+ * @param target the target to invoke {@code method} on
124
+ * @param args the function arguments. If the {@code Continuation} argument is specified as the last argument
125
+ * (typically {@code null}), it is ignored.
126
+ * @return the method invocation result as reactive stream
127
+ * @throws IllegalArgumentException if {@code method} is not a suspending function
128
+ * @since 6.0
129
+ * This function preservers the null parameter passed in argument
130
+ */
131
+ @ SuppressWarnings ({"DataFlowIssue" , "NullAway" })
132
+ public static Publisher <?> invokeSuspendingFunctionPreserveNulls (
133
+ CoroutineContext context , Method method , @ Nullable Object target , @ Nullable Object ... args ) {
134
+ return invokeSuspendingFunctionCore (context , method , target , args , true );
135
+ }
136
+
137
+ private static Publisher <?> invokeSuspendingFunctionCore (
138
+ CoroutineContext context ,
139
+ Method method ,
140
+ @ Nullable Object target ,
141
+ @ Nullable Object [] args ,
142
+ boolean preserveNulls )
143
+ {
115
144
116
145
Assert .isTrue (KotlinDetector .isSuspendingFunction (method ), "Method must be a suspending function" );
117
146
KFunction <?> function = ReflectJvmMapping .getKotlinFunction (method );
@@ -120,26 +149,7 @@ public static Publisher<?> invokeSuspendingFunction(
120
149
KCallablesJvm .setAccessible (function , true );
121
150
}
122
151
Mono <Object > mono = MonoKt .mono (context , (scope , continuation ) -> {
123
- Map <KParameter , Object > argMap = CollectionUtils .newHashMap (args .length + 1 );
124
- int index = 0 ;
125
- for (KParameter parameter : function .getParameters ()) {
126
- switch (parameter .getKind ()) {
127
- case INSTANCE -> argMap .put (parameter , target );
128
- case VALUE , EXTENSION_RECEIVER -> {
129
- Object arg = args [index ];
130
- if (!(parameter .isOptional () && arg == null )) {
131
- KType type = parameter .getType ();
132
- if (!(type .isMarkedNullable () && arg == null ) &&
133
- type .getClassifier () instanceof KClass <?> kClass &&
134
- KotlinDetector .isInlineClass (JvmClassMappingKt .getJavaClass (kClass ))) {
135
- arg = box (kClass , arg );
136
- }
137
- argMap .put (parameter , arg );
138
- }
139
- index ++;
140
- }
141
- }
142
- }
152
+ Map <KParameter , Object > argMap = buildArgMap (function , target , args , preserveNulls );
143
153
return KCallables .callSuspendBy (function , argMap , continuation );
144
154
})
145
155
.filter (result -> result != Unit .INSTANCE )
@@ -158,6 +168,40 @@ public static Publisher<?> invokeSuspendingFunction(
158
168
return mono ;
159
169
}
160
170
171
+ private static Map <KParameter , Object > buildArgMap (
172
+ KFunction <?> function ,
173
+ @ Nullable Object target ,
174
+ @ Nullable Object [] args ,
175
+ boolean preserveNulls ) {
176
+
177
+ Map <KParameter , Object > argMap = CollectionUtils .newHashMap (args .length + 1 );
178
+ int index = 0 ;
179
+
180
+ for (KParameter parameter : function .getParameters ()) {
181
+ switch (parameter .getKind ()) {
182
+ case INSTANCE -> argMap .put (parameter , target );
183
+ case VALUE , EXTENSION_RECEIVER -> {
184
+ Object arg = args [index ];
185
+
186
+ if (!(parameter .isOptional () && arg == null )) {
187
+ KType type = parameter .getType ();
188
+ if (!(type .isMarkedNullable () && arg == null ) &&
189
+ type .getClassifier () instanceof KClass <?> kClass &&
190
+ KotlinDetector .isInlineClass (JvmClassMappingKt .getJavaClass (kClass ))) {
191
+ arg = box (kClass , arg );
192
+ }
193
+ argMap .put (parameter , arg );
194
+ } else if (preserveNulls ) {
195
+ argMap .put (parameter , arg );
196
+ }
197
+ index ++;
198
+ }
199
+ }
200
+ }
201
+ return argMap ;
202
+ }
203
+
204
+
161
205
private static Object box (KClass <?> kClass , @ Nullable Object arg ) {
162
206
KFunction <?> constructor = Objects .requireNonNull (KClasses .getPrimaryConstructor (kClass ));
163
207
KType type = constructor .getParameters ().get (0 ).getType ();
0 commit comments