diff --git a/spring-cloud-function-samples/function-sample-aws/pom.xml b/spring-cloud-function-samples/function-sample-aws/pom.xml
index ee6ee3a41..5fc086c0f 100644
--- a/spring-cloud-function-samples/function-sample-aws/pom.xml
+++ b/spring-cloud-function-samples/function-sample-aws/pom.xml
@@ -14,7 +14,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.1.0.BUILD-SNAPSHOT
+ 2.1.0.RC1
diff --git a/spring-cloud-function-samples/function-sample-azure/pom.xml b/spring-cloud-function-samples/function-sample-azure/pom.xml
index 79a74e3ea..9fc7534cf 100644
--- a/spring-cloud-function-samples/function-sample-azure/pom.xml
+++ b/spring-cloud-function-samples/function-sample-azure/pom.xml
@@ -13,7 +13,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.1.0.M4
+ 2.1.0.RC1
diff --git a/spring-cloud-function-samples/function-sample-compiler/pom.xml b/spring-cloud-function-samples/function-sample-compiler/pom.xml
index 86ca518eb..b0834d60b 100644
--- a/spring-cloud-function-samples/function-sample-compiler/pom.xml
+++ b/spring-cloud-function-samples/function-sample-compiler/pom.xml
@@ -13,7 +13,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.1.0.M1
+ 2.1.0.RC1
@@ -22,7 +22,7 @@
2.0.0.BUILD-SNAPSHOT
Fishtown.BUILD-SNAPSHOT
3.1.2.RELEASE
- 1.0.10.RELEASE
+ 1.0.17.RELEASE
diff --git a/spring-cloud-function-samples/function-sample-pof/pom.xml b/spring-cloud-function-samples/function-sample-pof/pom.xml
index 7313c6886..38b153c28 100644
--- a/spring-cloud-function-samples/function-sample-pof/pom.xml
+++ b/spring-cloud-function-samples/function-sample-pof/pom.xml
@@ -12,7 +12,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.1.0.M1
+ 2.1.0.RC1
diff --git a/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java b/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java
index 000cb1dda..112334157 100644
--- a/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java
+++ b/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java
@@ -18,6 +18,7 @@ package com.example;
import java.net.URI;
import java.util.Arrays;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,40 +42,38 @@ public class SampleApplicationTests {
@LocalServerPort
private int port;
+ private TestRestTemplate rest = new TestRestTemplate();
@Test
public void words() {
- assertThat(new TestRestTemplate()
- .getForObject("http://localhost:" + port + "/words", String.class))
+ assertThat(rest.getForObject("http://localhost:" + port + "/words", String.class))
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
}
@Test
public void uppercase() {
- assertThat(new TestRestTemplate().postForObject(
- "http://localhost:" + port + "/uppercase", "[{\"value\":\"foo\"}]",
- String.class)).isEqualTo("[{\"value\":\"FOO\"}]");
+ assertThat(rest.postForObject("http://localhost:" + port + "/uppercase",
+ "[{\"value\":\"foo\"}]", String.class))
+ .isEqualTo("[{\"value\":\"FOO\"}]");
}
@Test
public void composite() {
- assertThat(new TestRestTemplate()
- .getForObject("http://localhost:" + port + "/words,uppercase", String.class))
- .isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
+ assertThat(rest.getForObject("http://localhost:" + port + "/words,uppercase",
+ String.class)).isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
}
@Test
public void single() {
- assertThat(new TestRestTemplate().postForObject(
- "http://localhost:" + port + "/uppercase", "{\"value\":\"foo\"}",
- String.class)).isEqualTo("{\"value\":\"FOO\"}");
+ assertThat(rest.postForObject("http://localhost:" + port + "/uppercase",
+ "{\"value\":\"foo\"}", String.class)).isEqualTo("{\"value\":\"FOO\"}");
}
@Test
public void lowercase() {
- assertThat(new TestRestTemplate().postForObject(
- "http://localhost:" + port + "/lowercase", "[{\"value\":\"Foo\"}]",
- String.class)).isEqualTo("[{\"value\":\"foo\"}]");
+ assertThat(rest.postForObject("http://localhost:" + port + "/lowercase",
+ "[{\"value\":\"Foo\"}]", String.class))
+ .isEqualTo("[{\"value\":\"foo\"}]");
}
@Test
@@ -85,10 +84,25 @@ public class SampleApplicationTests {
map.put("A", Arrays.asList("1", "2", "3"));
map.put("B", Arrays.asList("5", "6"));
- assertThat(new TestRestTemplate().exchange(RequestEntity.post(new URI("http://localhost:" + port + "/sum"))
- .accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_FORM_URLENCODED)
- .body(map), String.class).getBody())
- .isEqualTo("[{\"A\":6,\"B\":11}]");
+ assertThat(rest.exchange(
+ RequestEntity.post(new URI("http://localhost:" + port + "/sum"))
+ .accept(MediaType.APPLICATION_JSON)
+ .contentType(MediaType.APPLICATION_FORM_URLENCODED).body(map),
+ String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]");
}
+ @Test
+ @Ignore
+ public void multipart() throws Exception {
+
+ LinkedMultiValueMap map = new LinkedMultiValueMap<>();
+
+ map.put("A", Arrays.asList("1", "2", "3"));
+ map.put("B", Arrays.asList("5", "6"));
+
+ assertThat(rest.exchange(
+ RequestEntity.post(new URI("http://localhost:" + port + "/sum")).accept(MediaType.APPLICATION_JSON)
+ .contentType(MediaType.MULTIPART_FORM_DATA).body(map),
+ String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]");
+ }
}
diff --git a/spring-cloud-function-samples/function-sample/pom.xml b/spring-cloud-function-samples/function-sample/pom.xml
index 810a4f5cb..710e8dff8 100644
--- a/spring-cloud-function-samples/function-sample/pom.xml
+++ b/spring-cloud-function-samples/function-sample/pom.xml
@@ -13,14 +13,14 @@
org.springframework.boot
spring-boot-starter-parent
- 2.1.0.M1
+ 2.1.0.RC1
1.8
2.0.0.BUILD-SNAPSHOT
- 1.0.13.RELEASE
+ 1.0.17.RELEASE
diff --git a/spring-cloud-function-web/pom.xml b/spring-cloud-function-web/pom.xml
index 1fa994faa..c138ba438 100644
--- a/spring-cloud-function-web/pom.xml
+++ b/spring-cloud-function-web/pom.xml
@@ -60,6 +60,11 @@
spring-boot-configuration-processor
true
+
+ org.synchronoss.cloud
+ nio-multipart-parser
+ test
+
diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java
index ae38f3bfa..b4132949f 100644
--- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java
+++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java
@@ -16,6 +16,8 @@
package org.springframework.cloud.function.web;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -97,15 +99,14 @@ public class RequestProcessor {
boolean stream) {
Object function = wrapper.handler();
Class> inputType = inspector.getInputType(function);
+ Type itemType = getItemType(function);
Object input = null;
if (StringUtils.hasText(body)) {
if (body.startsWith("[")) {
- input = Collection.class.isAssignableFrom(inputType)
- ? mapper.toObject(body, inputType)
- : mapper.toObject(body,
- ResolvableType.forClassWithGenerics(ArrayList.class,
- (Class>) inputType).getType());
+ input = mapper.toObject(body, ResolvableType
+ .forClassWithGenerics(ArrayList.class, (Class>) itemType)
+ .getType());
}
else {
if (inputType == String.class) {
@@ -146,8 +147,8 @@ public class RequestProcessor {
form.putAll(params);
}
- boolean inputIsCollection =
- Collection.class.isAssignableFrom(inspector.getInputType(wrapper.handler()));
+ boolean inputIsCollection = Collection.class
+ .isAssignableFrom(inspector.getInputType(wrapper.handler()));
Flux> flux = body == null ? Flux.just(form)
: inputIsCollection ? Flux.just(body) : Flux.fromIterable(iterable);
if (inspector.isMessage(function)) {
@@ -254,6 +255,42 @@ public class RequestProcessor {
return Mono.from(function.apply(input));
}
+ private Object getTargetFunction(Object function) {
+ // we need to get the actual un-fluxed function so we can interrogate for types
+ Object target = inspector.getRegistration(function).getTarget();
+ if (target instanceof FluxWrapper) {
+ target = ((FluxWrapper>) target).getTarget();
+ }
+ return target;
+ }
+
+ private Type getItemType(Object function) {
+ Class> inputType = inspector.getInputType(function);
+ if (!Collection.class.isAssignableFrom(inputType)) {
+ return inputType;
+ }
+ Type type = inspector.getRegistration(this.getTargetFunction(function)).getType()
+ .getType();
+ if (type instanceof ParameterizedType) {
+ type = ((ParameterizedType) type).getActualTypeArguments()[0];
+ }
+ else {
+ for (Type iface : ((Class>) type).getGenericInterfaces()) {
+ if (iface.getTypeName().startsWith("java.util.function")) {
+ type = ((ParameterizedType) iface).getActualTypeArguments()[0];
+ break;
+ }
+ }
+ }
+ if (type instanceof ParameterizedType) {
+ type = ((ParameterizedType) type).getActualTypeArguments()[0];
+ }
+ else {
+ type = inputType;
+ }
+ return type;
+ }
+
public static class FunctionWrapper {
private final Function, Publisher>> function;
diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputCollectionTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputCollectionTests.java
index 3cf0eddf4..9367b43a5 100644
--- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputCollectionTests.java
+++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputCollectionTests.java
@@ -18,6 +18,7 @@ package org.springframework.cloud.function.test;
import java.util.List;
import java.util.function.Function;
+import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,15 +46,43 @@ public class FunctionalWithInputCollectionTests {
@Test
public void words() throws Exception {
- client.post().uri("/").body(Mono.just("[\"foo\", \"bar\"]"), String.class).exchange()
- .expectStatus().isOk().expectBody(String.class).isEqualTo("[FOO, BAR]");
+ client.post().uri("/").body(Mono.just("[{\"value\":\"foo\"}, {\"value\":\"bar\"}]"), String.class)
+ .exchange().expectStatus().isOk().expectBody(String.class)
+ .isEqualTo("{\"value\":\"FOOBAR\"}");
}
@SpringBootConfiguration
- protected static class TestConfiguration implements Function, String> {
+ protected static class TestConfiguration implements Function, Foo> {
@Override
- public String apply(List value) {
- return value.toString().toUpperCase();
+ public Foo apply(List value) {
+ return new Foo(value.stream().map(foo -> foo.getValue().toUpperCase())
+ .collect(Collectors.joining()));
}
}
+
+ public static class Foo {
+
+ private String value;
+
+ public Foo() {
+ }
+
+ public Foo(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return "Foo [value=" + this.value + "]";
+ }
+
+ }
}