Extract common code from BeanFactoryAwareFunctionRegistry

. . . to ensure that we can have the version of FunctionRegistry that is not dependent on BeanFactory.
This commit is contained in:
Oleg Zhurakousky
2020-04-16 10:00:25 +02:00
parent adbbbac677
commit f1c15bf950
16 changed files with 1030 additions and 776 deletions

View File

@@ -39,8 +39,8 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry.FunctionInvocationWrapper;
import org.springframework.cloud.function.context.catalog.FunctionInspector;
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper;
import org.springframework.cloud.function.context.config.RoutingFunction;
import org.springframework.cloud.function.context.message.MessageUtils;
import org.springframework.cloud.function.core.FluxConsumer;

View File

@@ -24,6 +24,7 @@ import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.DisposableServer;
@@ -38,6 +39,7 @@ import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.FunctionalSpringApplication;
import org.springframework.cloud.function.context.catalog.FunctionInspector;
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper;
import org.springframework.cloud.function.context.config.ContextFunctionCatalogInitializer;
import org.springframework.cloud.function.json.JsonMapper;
import org.springframework.cloud.function.web.BasicStringConverter;
@@ -244,10 +246,15 @@ class FunctionEndpointFactory {
.andRoute(GET("/**"), request -> {
Object functionComponent = extract(request);
Class<T> outputType = (Class<T>) this.inspector.getOutputType(functionComponent);
if (functionComponent instanceof Supplier) {
// if (functionComponent instanceof Supplier) {
if (((FunctionInvocationWrapper) functionComponent).isSupplier()) {
Supplier<? extends Flux<?>> supplier = (Supplier<Flux<?>>) functionComponent;
FunctionWrapper wrapper = RequestProcessor.wrapper(null, null, supplier);
return ServerResponse.ok().body(wrapper.supplier().get(), outputType);
Object result = wrapper.supplier().get();
if (!(result instanceof Publisher)) {
result = Mono.just(result);
}
return ServerResponse.ok().body(result, outputType);
}
else {
Function<Flux<?>, Flux<?>> function = (Function<Flux<?>, Flux<?>>) functionComponent;

View File

@@ -58,7 +58,7 @@ public class FunctionalExporterTests {
@Autowired
private SupplierExporter forwarder;
private static RestConfiguration app;
private static RestPojoConfiguration app;
private static ConfigurableApplicationContext context;
@@ -67,9 +67,9 @@ public class FunctionalExporterTests {
String port = "" + SocketUtils.findAvailableTcpPort();
System.setProperty("server.port", port);
System.setProperty("my.port", port);
context = SpringApplication.run(RestConfiguration.class,
context = SpringApplication.run(RestPojoConfiguration.class,
"--spring.main.web-application-type=reactive");
app = context.getBean(RestConfiguration.class);
app = context.getBean(RestPojoConfiguration.class);
// Sometimes the server doesn't start quick enough
Thread.sleep(500L);
}
@@ -97,8 +97,8 @@ public class FunctionalExporterTests {
protected static class ApplicationConfiguration
implements ApplicationContextInitializer<GenericApplicationContext> {
Function<Message<String>, Message<String>> uppercase() {
return value -> MessageBuilder.withPayload(value.getPayload().toUpperCase())
Function<Message<Person>, Message<String>> uppercase() {
return value -> MessageBuilder.withPayload(value.getPayload().getName().toUpperCase())
.copyHeaders(value.getHeaders()).build();
}
@@ -106,9 +106,20 @@ public class FunctionalExporterTests {
public void initialize(GenericApplicationContext context) {
context.registerBean("uppercase", FunctionRegistration.class,
() -> new FunctionRegistration<>(uppercase()).type(
FunctionType.from(String.class).to(String.class).message()));
FunctionType.from(Person.class).to(String.class).message()));
}
}
}
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2018-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.function.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@SpringBootConfiguration
@EnableAutoConfiguration
@RestController
public class RestPojoConfiguration {
private static Log logger = LogFactory.getLog(RestPojoConfiguration.class);
List<String> inputs = new ArrayList<>();
private Iterator<String> outputs = Arrays.asList("{\"name\":\"hello\"}").iterator();
@GetMapping("/")
ResponseEntity<String> home() {
logger.info("HOME");
if (this.outputs.hasNext()) {
return ResponseEntity.ok(this.outputs.next());
}
return ResponseEntity.notFound().build();
}
@PostMapping("/")
ResponseEntity<String> accept(@RequestBody String body) {
logger.info("ACCEPT");
this.inputs.add(body);
return ResponseEntity.accepted().body(body);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(RestPojoConfiguration.class, args);
}
}

View File

@@ -96,9 +96,10 @@ public class FunctionEndpointInitializerTests {
FunctionalSpringApplication.run(ApplicationConfiguration.class);
TestRestTemplate testRestTemplate = new TestRestTemplate();
String port = System.getProperty("server.port");
Thread.sleep(200);
Thread.sleep(2000);
ResponseEntity<String> response = testRestTemplate
.getForEntity(new URI("http://localhost:" + port + "/reverse/stressed"), String.class);
System.out.println();
assertThat(response.getBody()).isEqualTo("desserts");
}
@@ -131,7 +132,9 @@ public class FunctionEndpointInitializerTests {
}
public Function<String, String> reverse() {
return s -> new StringBuilder(s).reverse().toString();
return s -> {
return new StringBuilder(s).reverse().toString();
};
}
@Override