Convert Consumer<Foo> to Function<Flux<Foo>,Mono<Void>>
This results in a better experience for users because the consumer that they write is only applied to a Flux that is subscribed to by the framework once. It gives better control over the flow of foos, e.g. if some component wants to subscribe on a thread.
This commit is contained in:
@@ -405,23 +405,22 @@ public class ContextFunctionCatalogAutoConfiguration {
|
||||
findType(target);
|
||||
}
|
||||
Class<?> type;
|
||||
target = target(target, key);
|
||||
registration.target(target);
|
||||
if (target instanceof Supplier) {
|
||||
type = Supplier.class;
|
||||
registration.target(target((Supplier<?>) target, key));
|
||||
for (String name : registration.getNames()) {
|
||||
this.suppliers.put(name, registration.getTarget());
|
||||
}
|
||||
}
|
||||
else if (target instanceof Consumer) {
|
||||
type = Consumer.class;
|
||||
registration.target(target((Consumer<?>) target, key));
|
||||
for (String name : registration.getNames()) {
|
||||
this.consumers.put(name, registration.getTarget());
|
||||
}
|
||||
}
|
||||
else if (target instanceof Function) {
|
||||
type = Function.class;
|
||||
registration.target(target((Function<?, ?>) target, key));
|
||||
for (String name : registration.getNames()) {
|
||||
this.functions.put(name, registration.getTarget());
|
||||
}
|
||||
@@ -454,34 +453,34 @@ public class ContextFunctionCatalogAutoConfiguration {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private <T> T target(T target, String key) {
|
||||
private Object target(Object target, String key) {
|
||||
boolean isolated = getClass().getClassLoader() != target.getClass()
|
||||
.getClassLoader();
|
||||
if (target instanceof Supplier<?>) {
|
||||
boolean flux = isFluxSupplier(key, (Supplier<?>) target);
|
||||
if (isolated) {
|
||||
target = (T) new IsolatedSupplier((Supplier<?>) target);
|
||||
target = new IsolatedSupplier((Supplier<?>) target);
|
||||
}
|
||||
if (!flux) {
|
||||
target = (T) new FluxSupplier((Supplier<?>) target);
|
||||
target = new FluxSupplier((Supplier<?>) target);
|
||||
}
|
||||
}
|
||||
else if (target instanceof Function<?, ?>) {
|
||||
boolean flux = isFluxFunction(key, (Function<?, ?>) target);
|
||||
if (isolated) {
|
||||
target = (T) new IsolatedFunction((Function<?, ?>) target);
|
||||
target = new IsolatedFunction((Function<?, ?>) target);
|
||||
}
|
||||
if (!flux) {
|
||||
target = (T) new FluxFunction((Function<?, ?>) target);
|
||||
target = new FluxFunction((Function<?, ?>) target);
|
||||
}
|
||||
}
|
||||
else if (target instanceof Consumer<?>) {
|
||||
boolean flux = isFluxConsumer(key, (Consumer<?>) target);
|
||||
if (isolated) {
|
||||
target = (T) new IsolatedConsumer((Consumer<?>) target);
|
||||
target = new IsolatedConsumer((Consumer<?>) target);
|
||||
}
|
||||
if (!flux) {
|
||||
target = (T) new FluxConsumer((Consumer<?>) target);
|
||||
target = new FluxConsumer((Consumer<?>) target);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.cloud.function.context.config.ContextFunctionCatalogA
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -88,7 +89,8 @@ public class BeanFactoryFunctionCatalogTests {
|
||||
public void composeFunction() {
|
||||
processor.register(new FunctionRegistration<>(new Foos()).names("foos"));
|
||||
processor.register(new FunctionRegistration<>(new Bars()).names("bars"));
|
||||
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "foos,bars");
|
||||
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class,
|
||||
"foos,bars");
|
||||
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4");
|
||||
}
|
||||
|
||||
@@ -112,8 +114,9 @@ public class BeanFactoryFunctionCatalogTests {
|
||||
processor.register(new FunctionRegistration<>(new Foos()).names("foos"));
|
||||
Sink sink = new Sink();
|
||||
processor.register(new FunctionRegistration<>(sink).names("sink"));
|
||||
Consumer<Flux<Integer>> foos = processor.lookup(Consumer.class, "foos,sink");
|
||||
foos.accept(Flux.just(2));
|
||||
Function<Flux<Integer>, Mono<Void>> foos = processor.lookup(Function.class,
|
||||
"foos,sink");
|
||||
foos.apply(Flux.just(2)).subscribe();
|
||||
assertThat(sink.values).contains("4");
|
||||
}
|
||||
|
||||
@@ -121,8 +124,8 @@ public class BeanFactoryFunctionCatalogTests {
|
||||
public void composeUniqueConsumer() {
|
||||
Sink sink = new Sink();
|
||||
processor.register(new FunctionRegistration<>(sink).names("sink"));
|
||||
Consumer<Flux<String>> foos = processor.lookup(Consumer.class, "");
|
||||
foos.accept(Flux.just("2"));
|
||||
Function<Flux<String>, Mono<Void>> foos = processor.lookup(Function.class, "");
|
||||
foos.apply(Flux.just("2")).subscribe();
|
||||
assertThat(sink.values).contains("2");
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import org.springframework.util.StreamUtils;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -115,11 +116,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
|
||||
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
|
||||
.isInstanceOf(Function.class);
|
||||
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos"))
|
||||
.isInstanceOf(Consumer.class);
|
||||
assertThat(catalog.<Supplier<?>>lookup(Supplier.class, "foos"))
|
||||
.isInstanceOf(Supplier.class);
|
||||
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
|
||||
.isEqualTo(String.class);
|
||||
assertThat(inspector.getInputType(catalog.lookup(Consumer.class, "foos")))
|
||||
assertThat(inspector.getOutputType(catalog.lookup(Supplier.class, "foos")))
|
||||
.isEqualTo(Foo.class);
|
||||
}
|
||||
|
||||
@@ -185,13 +186,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
@Test
|
||||
public void composedConsumer() {
|
||||
create(MultipleConfiguration.class);
|
||||
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos,print"))
|
||||
.isInstanceOf(Consumer.class);
|
||||
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos,print")).isNull();
|
||||
assertThat(inspector.getInputType(catalog.lookup(Consumer.class, "foos,print")))
|
||||
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos,print")).isNull();
|
||||
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos,print"))
|
||||
.isInstanceOf(Function.class);
|
||||
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos,print")))
|
||||
.isAssignableFrom(String.class);
|
||||
// The output type is the same as the output type of the last element in the chain
|
||||
assertThat(inspector.getOutputType(catalog.lookup(Consumer.class, "foos,print")))
|
||||
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos,print")))
|
||||
.isAssignableFrom(Void.class);
|
||||
}
|
||||
|
||||
@@ -391,8 +392,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
public void simpleConsumer() {
|
||||
create(SimpleConfiguration.class);
|
||||
assertThat(context.getBean("consumer")).isInstanceOf(Consumer.class);
|
||||
Consumer<Flux<String>> consumer = catalog.lookup(Consumer.class, "consumer");
|
||||
consumer.accept(Flux.just("foo", "bar"));
|
||||
Function<Flux<String>, Mono<Void>> consumer = catalog.lookup(Function.class,
|
||||
"consumer");
|
||||
consumer.apply(Flux.just("foo", "bar")).subscribe();
|
||||
assertThat(context.getBean(SimpleConfiguration.class).list).hasSize(2);
|
||||
}
|
||||
|
||||
@@ -464,9 +466,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
+ "::set",
|
||||
"spring.cloud.function.compile.foos.type=consumer",
|
||||
"spring.cloud.function.compile.foos.inputType=String");
|
||||
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos"))
|
||||
.isInstanceOf(Consumer.class);
|
||||
assertThat(inspector.getInputWrapper(catalog.lookup(Consumer.class, "foos")))
|
||||
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
|
||||
.isInstanceOf(Function.class);
|
||||
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
|
||||
.isEqualTo(String.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<String> consumer = (Consumer<String>) context.getBean("foos");
|
||||
@@ -602,7 +604,6 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
protected static class AmbiguousConfiguration {
|
||||
private List<Foo> list = new ArrayList<>();
|
||||
|
||||
@Bean
|
||||
public Function<String, Foo> foos() {
|
||||
@@ -611,8 +612,8 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
|
||||
@Bean
|
||||
@Qualifier("foos")
|
||||
public Consumer<Foo> consumer() {
|
||||
return value -> list.add(value);
|
||||
public Supplier<Foo> supplier() {
|
||||
return () -> new Foo("bar");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,15 @@ import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration.ContextFunctionRegistry;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -124,7 +125,8 @@ public class ContextFunctionPostProcessorTests {
|
||||
assertThat(foos.get().blockFirst()).isEqualTo("8");
|
||||
assertThat(processor.getRegistration(foos).getNames())
|
||||
.containsExactly("ints|foos");
|
||||
assertThat(processor.getRegistration(foos).getType().getOutputWrapper()).isEqualTo(Flux.class);
|
||||
assertThat(processor.getRegistration(foos).getType().getOutputWrapper())
|
||||
.isEqualTo(Flux.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -157,9 +159,9 @@ public class ContextFunctionPostProcessorTests {
|
||||
Object target = create(Sink.class);
|
||||
processor.register(new FunctionRegistration<>(target).names("sink"));
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<Flux<String>> sink = (Consumer<Flux<String>>) processor
|
||||
.lookupConsumer("sink");
|
||||
sink.accept(Flux.just("Hello"));
|
||||
Function<Flux<String>, Mono<Void>> sink = (Function<Flux<String>, Mono<Void>>) processor
|
||||
.lookupFunction("sink");
|
||||
sink.apply(Flux.just("Hello")).subscribe();
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> values = (List<String>) ReflectionTestUtils.getField(target,
|
||||
"values");
|
||||
|
||||
Reference in New Issue
Block a user