@@ -112,6 +112,35 @@ public static Publisher<?> invokeSuspendingFunction(Method method, Object target
112112 @ SuppressWarnings ({"DataFlowIssue" , "NullAway" })
113113 public static Publisher <?> invokeSuspendingFunction (
114114 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+ {
115144
116145 Assert .isTrue (KotlinDetector .isSuspendingFunction (method ), "Method must be a suspending function" );
117146 KFunction <?> function = ReflectJvmMapping .getKotlinFunction (method );
@@ -120,26 +149,7 @@ public static Publisher<?> invokeSuspendingFunction(
120149 KCallablesJvm .setAccessible (function , true );
121150 }
122151 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 );
143153 return KCallables .callSuspendBy (function , argMap , continuation );
144154 })
145155 .filter (result -> result != Unit .INSTANCE )
@@ -158,6 +168,40 @@ public static Publisher<?> invokeSuspendingFunction(
158168 return mono ;
159169 }
160170
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+
161205 private static Object box (KClass <?> kClass , @ Nullable Object arg ) {
162206 KFunction <?> constructor = Objects .requireNonNull (KClasses .getPrimaryConstructor (kClass ));
163207 KType type = constructor .getParameters ().get (0 ).getType ();
0 commit comments