Skip to content

Commit 67180ac

Browse files
committed
1144 Fix propagation of skipInputConversion
Resolves #1144
1 parent 953217f commit 67180ac

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,8 @@ public class FunctionInvocationWrapper implements Function<Object, Object>, Cons
422422

423423
private PostProcessingFunction postProcessor;
424424

425+
private Consumer<Boolean> skipInputConversionCallback;
426+
425427
/*
426428
* This is primarily to support Stream's ability to access
427429
* un-converted payload (e.g., to evaluate expression on some attribute of a payload)
@@ -483,6 +485,9 @@ public boolean isSkipOutputConversion() {
483485
return skipOutputConversion;
484486
}
485487

488+
public boolean isSkipInputConversion() {
489+
return skipInputConversion;
490+
}
486491

487492
public boolean isPrototype() {
488493
return !this.isSingleton;
@@ -493,6 +498,13 @@ public void setSkipInputConversion(boolean skipInputConversion) {
493498
logger.debug("'skipInputConversion' was explicitely set to true. No input conversion will be attempted");
494499
}
495500
this.skipInputConversion = skipInputConversion;
501+
if (this.skipInputConversionCallback != null) {
502+
this.skipInputConversionCallback.accept(skipInputConversion);
503+
}
504+
}
505+
506+
void setSkipInputConversionCallback(Consumer<Boolean> skipInputConversionCallback) {
507+
this.skipInputConversionCallback = skipInputConversionCallback;
496508
}
497509

498510
public void setSkipOutputConversion(boolean skipOutputConversion) {
@@ -684,6 +696,10 @@ else if (this.outputType == null) {
684696

685697
String composedName = this.functionDefinition + "|" + afterWrapper.functionDefinition;
686698
FunctionInvocationWrapper composedFunction = invocationWrapperInstance(composedName, rawComposedFunction, composedFunctionType);
699+
composedFunction.setSkipInputConversionCallback((skipInputConversion) -> {
700+
this.setSkipInputConversion(skipInputConversion);
701+
afterWrapper.setSkipInputConversion(skipInputConversion);
702+
});
687703
composedFunction.composed = true;
688704
if (((FunctionInvocationWrapper) after).target instanceof PostProcessingFunction) {
689705
composedFunction.postProcessor = (PostProcessingFunction) ((FunctionInvocationWrapper) after).target;
@@ -836,7 +852,7 @@ private Object fluxifyInputIfNecessary(Object input) {
836852
if ((!treatPayloadAsPlainText && JsonMapper.isJsonStringRepresentsCollection(payload))
837853
&& !FunctionTypeUtils.isTypeCollection(this.inputType)
838854
&& !FunctionTypeUtils.isTypeArray(this.inputType)) {
839-
MessageHeaders headers = ((Message) input).getHeaders();
855+
MessageHeaders headers = input instanceof Message ? ((Message) input).getHeaders() : new MessageHeaders(Collections.emptyMap());
840856
Collection collectionPayload = jsonMapper.fromJson(payload, Collection.class);
841857
Class inputClass = FunctionTypeUtils.getRawType(this.inputType);
842858
if (this.isInputTypeMessage()) {
@@ -1103,6 +1119,9 @@ else if (FunctionTypeUtils.isMultipleArgumentType(type)) {
11031119
convertedInput = Tuples.fromArray(convertedInputs);
11041120
}
11051121
else if (this.skipInputConversion) {
1122+
if (!(input instanceof Message)) {
1123+
input = MessageBuilder.withPayload(input).build();
1124+
}
11061125
convertedInput = this.isInputTypeMessage()
11071126
? input
11081127
: new OriginalMessageHolder(((Message) input).getPayload(), (Message<?>) input);

spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ public void testCompositionWithNonExistingFunction() throws Exception {
140140
assertThat(registration.getNames().iterator().next()).isEqualTo("echo1");
141141
}
142142

143+
@SuppressWarnings({ "rawtypes", "unchecked" })
144+
@Test
145+
public void testMessageWithArrayAsPayload() throws Exception {
146+
FunctionCatalog catalog = this.configureCatalog(MessageWithArrayAsPayload.class);
147+
FunctionInvocationWrapper function = catalog.lookup("myFunction");
148+
149+
List payload = List.of("Ricky", "Julien", "Bubbles");
150+
151+
Message result = (Message) function.apply(MessageBuilder.withPayload(payload).build());
152+
153+
assertThat(((Collection) result.getPayload())).isNotEmpty();
154+
155+
}
156+
143157
@SuppressWarnings({ "rawtypes", "unchecked" })
144158
@Test
145159
public void testCompositionWithNullReturnInBetween() {
@@ -325,7 +339,7 @@ public void testReactiveVoidInputFunctionAsSupplier() {
325339

326340

327341
@Test
328-
public void testComposition() {
342+
public void testComposition() throws Exception {
329343
FunctionCatalog catalog = this.configureCatalog();
330344
Function<Flux<String>, Flux<String>> fluxFunction = catalog.lookup("uppercase|reverseFlux");
331345

@@ -348,8 +362,24 @@ public void testComposition() {
348362
assertThat(result.get(0)).isEqualTo("OLLEH");
349363
assertThat(result.get(1)).isEqualTo("EYB");
350364

351-
Function<String, String> function = catalog.lookup("uppercase|reverse");
365+
FunctionInvocationWrapper function = catalog.lookup("uppercase|reverse");
352366
assertThat(function.apply("foo")).isEqualTo("OOF");
367+
368+
Object target = function.getTarget();
369+
Field arg1Field = ReflectionUtils.findField(target.getClass(), "arg$1");
370+
arg1Field.setAccessible(true);
371+
FunctionInvocationWrapper functionUppercase = (FunctionInvocationWrapper) arg1Field.get(target);
372+
373+
Field arg2Field = ReflectionUtils.findField(target.getClass(), "arg$2");
374+
arg2Field.setAccessible(true);
375+
FunctionInvocationWrapper functionReverse = (FunctionInvocationWrapper) arg2Field.get(target);
376+
377+
assertThat(functionUppercase.isSkipInputConversion()).isFalse();
378+
assertThat(functionReverse.isSkipInputConversion()).isFalse();
379+
380+
function.setSkipInputConversion(true);
381+
assertThat(functionUppercase.isSkipInputConversion()).isTrue();
382+
assertThat(functionReverse.isSkipInputConversion()).isTrue();
353383
}
354384

355385
@Test
@@ -1509,4 +1539,13 @@ public Function<String, String> echo2() {
15091539
}
15101540
}
15111541

1542+
@EnableAutoConfiguration
1543+
@Configuration
1544+
public static class MessageWithArrayAsPayload {
1545+
1546+
@Bean
1547+
public Function<Message<?>, Message<?>> myFunction() {
1548+
return msg -> msg;
1549+
}
1550+
}
15121551
}

0 commit comments

Comments
 (0)