Fixed README generation and polished few tests
This commit is contained in:
@@ -45,9 +45,12 @@ https://www.reactive-streams.org/[Reactive Streams] `Publisher` from
|
||||
https://projectreactor.io/[Project Reactor]. The function can be
|
||||
accessed over HTTP or messaging.
|
||||
|
||||
*Features*
|
||||
Spring Cloud Function has 4 main features:
|
||||
|
||||
In the nutshell Spring Cloud Function provides the following features:
|
||||
1. Wrappers for `@Beans` of type `Function`, `Consumer` and
|
||||
`Supplier`, exposing them to the outside world as either HTTP
|
||||
endpoints and/or message stream listeners/publishers with RabbitMQ, Kafka etc.
|
||||
|
||||
* _Choice of programming styles - reactive, imperative or hybrid._
|
||||
* _Function composition and adaptation (e.g., composing imperative functions with reactive)._
|
||||
@@ -391,4 +394,4 @@ Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on t
|
||||
- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL.
|
||||
- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`.
|
||||
|
||||
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
|
||||
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
|
||||
@@ -7,7 +7,7 @@ Spring Cloud Function is a project with the following high-level goals:
|
||||
|
||||
It abstracts away all of the transport details and
|
||||
infrastructure, allowing the developer to keep all the familiar tools
|
||||
and processes, and focus firmly on business logic.
|
||||
and processes, and focus firmly on business logic.
|
||||
|
||||
Here's a complete, executable, testable Spring Boot application
|
||||
(implementing a simple string manipulation):
|
||||
@@ -37,15 +37,17 @@ accessed over HTTP or messaging.
|
||||
|
||||
Spring Cloud Function has 4 main features:
|
||||
|
||||
In the nutshell Spring Cloud Function provides the following features:
|
||||
1. Wrappers for `@Beans` of type `Function`, `Consumer` and
|
||||
`Supplier`, exposing them to the outside world as either HTTP
|
||||
endpoints and/or message stream listeners/publishers with RabbitMQ, Kafka etc.
|
||||
|
||||
2. Compiling strings which are Java function bodies into bytecode, and
|
||||
then turning them into `@Beans` that can be wrapped as above.
|
||||
|
||||
3. Deploying a JAR file containing such an application context with an
|
||||
isolated classloader, so that you can pack them together in a single
|
||||
JVM.
|
||||
|
||||
4. Adapters for https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-aws[AWS Lambda], https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-azure[Azure], https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk[Apache OpenWhisk] and possibly other "serverless" service providers.
|
||||
* _Choice of programming styles - reactive, imperative or hybrid._
|
||||
* _Function composition and adaptation (e.g., composing imperative functions with reactive)._
|
||||
* _Support for reactive function with multiple inputs and outputs allowing merging, joining and other complex streaming operation to be handled by functions._
|
||||
* _Transparent type conversion of inputs and outputs._
|
||||
* _Packaging functions for deployments, specific to the target platform (e.g., Project Riff, AWS Lambda and more)_
|
||||
* _Adapters to expose function to the outside world as HTTP endpoints etc._
|
||||
* _Deploying a JAR file containing such an application context with an isolated classloader, so that you can pack them together in a single JVM._
|
||||
* _Compiling strings which are Java function bodies into bytecode, and then turning them into `@Beans` that can be wrapped as above._
|
||||
* _Adapters for https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-aws[AWS Lambda], https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-azure[Azure], https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk[Apache OpenWhisk] and possibly other "serverless" service providers._
|
||||
@@ -430,6 +430,7 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs will be converted only if we're told how (via acceptedOutputMimeTypes), otherwise output returned as is.
|
||||
if (!ObjectUtils.isEmpty(this.acceptedOutputMimeTypes)) {
|
||||
result = result instanceof Publisher
|
||||
? this.convertOutputPublisherIfNecessary((Publisher<?>) result, this.acceptedOutputMimeTypes)
|
||||
@@ -462,7 +463,7 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
}
|
||||
convertedValue = Tuples.fromArray(convertedInputArray);
|
||||
}
|
||||
else {
|
||||
else if (value != null) {
|
||||
List<MimeType> acceptedContentTypes = MimeTypeUtils.parseMimeTypes(acceptedOutputMimeTypes[0].toString());
|
||||
|
||||
convertedValue = acceptedContentTypes.stream()
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -78,6 +79,28 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
assertThat(messageResult.get(1).getPayload()).isEqualTo("\"UPPERCASEFLUX2\"".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConsumerFunction() { // function that returns Void, effectively a Consumer
|
||||
FunctionCatalog catalog = this.configureCatalog();
|
||||
|
||||
Function<String, Void> consumerFunction = catalog.lookup("consumerFunction");
|
||||
assertThat(consumerFunction.apply("hello")).isNull();
|
||||
|
||||
Function<Message<byte[]>, Void> consumerFunctionAsMessageA = catalog.lookup("consumerFunction");
|
||||
assertThat(consumerFunctionAsMessageA.apply(new GenericMessage<byte[]>("\"hello\"".getBytes()))).isNull();
|
||||
|
||||
Function<Message<byte[]>, Void> consumerFunctionAsMessageB = catalog.lookup("consumerFunction", "application/json");
|
||||
assertThat(consumerFunctionAsMessageB.apply(new GenericMessage<byte[]>("\"hello\"".getBytes()))).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageToPojoConversion() {
|
||||
FunctionCatalog catalog = this.configureCatalog();
|
||||
Function<Message<String>, Person> uppercasePerson = catalog.lookup("uppercasePerson");
|
||||
Person person = uppercasePerson.apply(MessageBuilder.withPayload("{\"name\":\"bill\",\"id\":2}").build());
|
||||
assertThat(person.getName()).isEqualTo("BILL");
|
||||
}
|
||||
|
||||
/*
|
||||
* When invoking imperative function as reactive the rules are
|
||||
* - the input wrapper must match the output wrapper (e.g., <Flux, Flux> or <Mono, Mono>)
|
||||
@@ -249,6 +272,13 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
@Configuration
|
||||
protected static class SampleFunctionConfiguration {
|
||||
|
||||
@Bean
|
||||
public Function<Person, Person> uppercasePerson() {
|
||||
return person -> {
|
||||
return new Person(person.getName().toUpperCase(), person.getId());
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<String> numberword() {
|
||||
return () -> "one";
|
||||
@@ -267,6 +297,14 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
return v -> v.toUpperCase();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<String, Void> consumerFunction() {
|
||||
return v -> {
|
||||
System.out.println("Value: " + v);
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<String>, Flux<String>> uppercaseFlux() {
|
||||
return flux -> flux.map(v -> v.toUpperCase());
|
||||
@@ -392,10 +430,13 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Person {
|
||||
public static class Person {
|
||||
private String name;
|
||||
private int id;
|
||||
Person(String name, int id) {
|
||||
public Person() {
|
||||
|
||||
}
|
||||
public Person(String name, int id) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user