Change FunctionCatalog to key off Class<?>

Makes it possible to support other "function" types in the future.
The user is always taking a risk with the lookup that the object
returned has the generic type desired (but that hasn't changed
with this commit). FunctionCatalog is a lot simpler as a result
and also a lot more flexible.
This commit is contained in:
Dave Syer
2018-02-27 10:22:44 +00:00
parent c11a4454ff
commit 33b33adb4b
21 changed files with 498 additions and 407 deletions

View File

@@ -17,24 +17,14 @@
package org.springframework.cloud.function.context;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author Dave Syer
*/
public interface FunctionCatalog {
<T> Supplier<T> lookupSupplier(String name);
<T> T lookup(Class<?> type, String name);
<T, R> Function<T, R> lookupFunction(String name);
Set<String> getNames(Class<?> type);
<T> Consumer<T> lookupConsumer(String name);
Set<String> getSupplierNames();
Set<String> getFunctionNames();
Set<String> getConsumerNames();
}

View File

@@ -118,7 +118,7 @@ public class FunctionType {
}
public FunctionType wrap(Class<?> wrapper) {
if (wrapper.isAssignableFrom(getInputWrapper())) {
if (wrapper.isAssignableFrom(getInputWrapper()) || !isWrapper(wrapper)) {
return this;
}
return new FunctionType(ResolvableType.forClassWithGenerics(Function.class,

View File

@@ -16,24 +16,48 @@
package org.springframework.cloud.function.context.catalog;
import org.springframework.cloud.function.context.FunctionRegistration;
/**
* @author Dave Syer
*
*/
public interface FunctionInspector {
boolean isMessage(Object function);
FunctionRegistration<?> getRegistration(Object function);
Class<?> getInputType(Object function);
default boolean isMessage(Object function) {
FunctionRegistration<?> registration = getRegistration(function);
return registration == null ? false : registration.getType().isMessage();
}
Class<?> getOutputType(Object function);
default Class<?> getInputType(Object function) {
FunctionRegistration<?> registration = getRegistration(function);
return registration == null ? Object.class
: registration.getType().getInputType();
}
Class<?> getInputWrapper(Object function);
default Class<?> getOutputType(Object function) {
FunctionRegistration<?> registration = getRegistration(function);
return registration == null ? Object.class
: registration.getType().getOutputType();
}
Class<?> getOutputWrapper(Object function);
default Class<?> getInputWrapper(Object function) {
FunctionRegistration<?> registration = getRegistration(function);
return registration == null ? Object.class
: registration.getType().getInputWrapper();
}
Object convert(Object function, String value);
default Class<?> getOutputWrapper(Object function) {
FunctionRegistration<?> registration = getRegistration(function);
return registration == null ? Object.class
: registration.getType().getOutputWrapper();
}
String getName(Object function);
default String getName(Object function) {
FunctionRegistration<?> registration = getRegistration(function);
return registration == null ? null : registration.getNames().iterator().next();
}
}

View File

@@ -42,11 +42,7 @@ import org.springframework.util.Assert;
public class InMemoryFunctionCatalog
implements FunctionRegistry, ApplicationEventPublisherAware {
private final Map<String, Function<?, ?>> functions;
private final Map<String, Consumer<?>> consumers;
private final Map<String, Supplier<?>> suppliers;
private final Map<Class<?>, Map<String, Object>> functions;
@Autowired(required = false)
private ApplicationEventPublisher publisher;
@@ -57,49 +53,42 @@ public class InMemoryFunctionCatalog
public InMemoryFunctionCatalog(Set<FunctionRegistration<?>> registrations) {
Assert.notNull(registrations, "'registrations' must not be null");
this.suppliers = new HashMap<>();
this.functions = new HashMap<>();
this.consumers = new HashMap<>();
registrations.stream().forEach(reg -> reg.getNames().stream().forEach(name -> {
if (reg.getTarget() instanceof Consumer) {
consumers.put(name, (Consumer<?>) reg.getTarget());
}
else if (reg.getTarget() instanceof Function) {
functions.put(name, (Function<?, ?>) reg.getTarget());
}
else if (reg.getTarget() instanceof Supplier) {
suppliers.put(name, (Supplier<?>) reg.getTarget());
}
}));
registrations.stream().forEach(reg -> register(reg));
}
@Override
public <T> void register(FunctionRegistration<T> registration) {
Map<String, ?> values = null;
FunctionRegistrationEvent event;
Class<?> type;
if (registration.getTarget() instanceof Function) {
values = this.functions;
type = Function.class;
event = new FunctionRegistrationEvent(this, Function.class,
registration.getNames());
}
else if (registration.getTarget() instanceof Supplier) {
values = this.suppliers;
type = Supplier.class;
event = new FunctionRegistrationEvent(this, Supplier.class,
registration.getNames());
}
else {
values = this.consumers;
else if (registration.getTarget() instanceof Consumer) {
type = Consumer.class;
event = new FunctionRegistrationEvent(this, Consumer.class,
registration.getNames());
}
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) values;
else {
type = Object.class;
event = new FunctionRegistrationEvent(this, Object.class,
registration.getNames());
}
Map<String, Object> map = functions.computeIfAbsent(type, key -> new HashMap<>());
for (String name : registration.getNames()) {
map.put(name, registration.getTarget());
}
publisher.publishEvent(event);
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@@ -108,16 +97,10 @@ public class InMemoryFunctionCatalog
public void init() {
if (publisher != null) {
if (!functions.isEmpty()) {
publisher.publishEvent(new FunctionRegistrationEvent(this, Function.class,
functions.keySet()));
}
if (!consumers.isEmpty()) {
publisher.publishEvent(new FunctionRegistrationEvent(this, Consumer.class,
consumers.keySet()));
}
if (!suppliers.isEmpty()) {
publisher.publishEvent(new FunctionRegistrationEvent(this, Supplier.class,
suppliers.keySet()));
for (Class<?> type : functions.keySet()) {
publisher.publishEvent(new FunctionRegistrationEvent(this, type,
functions.get(type).keySet()));
}
}
}
}
@@ -126,50 +109,48 @@ public class InMemoryFunctionCatalog
public void close() {
if (publisher != null) {
if (!functions.isEmpty()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this,
Function.class, functions.keySet()));
}
if (!consumers.isEmpty()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this,
Consumer.class, consumers.keySet()));
}
if (!suppliers.isEmpty()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this,
Supplier.class, suppliers.keySet()));
for (Class<?> type : functions.keySet()) {
publisher.publishEvent(new FunctionUnregistrationEvent(this, type,
functions.get(type).keySet()));
}
}
}
}
@Override
@SuppressWarnings("unchecked")
public <T> Supplier<T> lookupSupplier(String name) {
return (Supplier<T>) suppliers.get(name);
public <T> T lookup(Class<?> type, String name) {
Map<String, Object> map = null;
for (Class<?> key : functions.keySet()) {
if (key != Object.class) {
if (key.isAssignableFrom(type)) {
map = functions.get(key);
break;
}
}
}
if (map == null) {
map = functions.get(Object.class);
}
@SuppressWarnings("unchecked")
T result = (T) map.get(name);
return result;
}
@Override
@SuppressWarnings("unchecked")
public <T, R> Function<T, R> lookupFunction(String name) {
return (Function<T, R>) functions.get(name);
public Set<String> getNames(Class<?> type) {
Map<String, Object> map = null;
for (Class<?> key : functions.keySet()) {
if (key != Object.class) {
if (key.isAssignableFrom(type)) {
map = functions.get(key);
break;
}
}
}
if (map == null) {
map = functions.get(Object.class);
}
return map == null ? Collections.emptySet() : map.keySet();
}
@Override
@SuppressWarnings("unchecked")
public <T> Consumer<T> lookupConsumer(String name) {
return (Consumer<T>) consumers.get(name);
}
@Override
public Set<String> getSupplierNames() {
return suppliers.keySet();
}
@Override
public Set<String> getFunctionNames() {
return functions.keySet();
}
@Override
public Set<String> getConsumerNames() {
return consumers.keySet();
}
}

View File

@@ -64,8 +64,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.io.Resource;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.core.type.classreading.MethodMetadataReadingVisitor;
@@ -119,38 +117,31 @@ public class ContextFunctionCatalogAutoConfiguration {
@Override
@SuppressWarnings("unchecked")
public <T> Supplier<T> lookupSupplier(String name) {
Supplier<T> result = (Supplier<T>) processor.lookupSupplier(name);
return result;
public <T> T lookup(Class<?> type, String name) {
if (Supplier.class.isAssignableFrom(type)) {
return (T) processor.lookupSupplier(name);
}
if (Consumer.class.isAssignableFrom(type)) {
return (T) processor.lookupConsumer(name);
}
if (Function.class.isAssignableFrom(type)) {
return (T) processor.lookupFunction(name);
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public <T, R> Function<T, R> lookupFunction(String name) {
Function<T, R> result = (Function<T, R>) processor.lookupFunction(name);
return result;
}
@Override
@SuppressWarnings("unchecked")
public <T> Consumer<T> lookupConsumer(String name) {
Consumer<T> result = (Consumer<T>) processor.lookupConsumer(name);
return result;
}
@Override
public Set<String> getSupplierNames() {
return this.processor.getSuppliers();
}
@Override
public Set<String> getFunctionNames() {
return this.processor.getFunctions();
}
@Override
public Set<String> getConsumerNames() {
return this.processor.getConsumers();
public Set<String> getNames(Class<?> type) {
if (Supplier.class.isAssignableFrom(type)) {
return this.processor.getSuppliers();
}
if (Consumer.class.isAssignableFrom(type)) {
return this.processor.getConsumers();
}
if (Function.class.isAssignableFrom(type)) {
return this.processor.getFunctions();
}
return Collections.emptySet();
}
public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) {
@@ -168,38 +159,8 @@ public class ContextFunctionCatalogAutoConfiguration {
}
@Override
public boolean isMessage(Object function) {
return processor.isMessage(function);
}
@Override
public Class<?> getInputWrapper(Object function) {
return processor.findType(function).getInputWrapper();
}
@Override
public Class<?> getOutputWrapper(Object function) {
return processor.findType(function).getOutputWrapper();
}
@Override
public Class<?> getInputType(Object function) {
return processor.findType(function).getInputType();
}
@Override
public Class<?> getOutputType(Object function) {
return processor.findType(function).getOutputType();
}
@Override
public Object convert(Object function, String value) {
return processor.convert(function, value);
}
@Override
public String getName(Object function) {
return processor.registrations.get(function);
public FunctionRegistration<?> getRegistration(Object function) {
return processor.getRegistration(function);
}
}
@@ -219,9 +180,7 @@ public class ContextFunctionCatalogAutoConfiguration {
@Autowired
private ConfigurableListableBeanFactory registry;
private ConversionService conversionService;
private Map<Object, String> registrations = new HashMap<>();
private Map<Object, String> names = new HashMap<>();
private Map<String, FunctionType> types = new HashMap<>();
@@ -229,6 +188,14 @@ public class ContextFunctionCatalogAutoConfiguration {
return this.suppliers.keySet();
}
public FunctionRegistration<?> getRegistration(Object function) {
if (!names.containsKey(function)) {
return null;
}
return new FunctionRegistration<>(function).name(names.get(function))
.type(findType(function).getType());
}
public Set<String> getConsumers() {
return this.consumers.keySet();
}
@@ -302,7 +269,7 @@ public class ContextFunctionCatalogAutoConfiguration {
types.put(name, FunctionType.compose(input, output));
}
}
registrations.put(function, name);
names.put(function, name);
return function;
}
@@ -413,19 +380,6 @@ public class ContextFunctionCatalogAutoConfiguration {
return registrations;
}
private Object convert(Object function, String value) {
if (conversionService == null && registry != null) {
ConversionService conversionService = this.registry
.getConversionService();
this.conversionService = conversionService != null ? conversionService
: new DefaultConversionService();
}
Class<?> type = findType(function).getInputType();
return conversionService.canConvert(String.class, type)
? conversionService.convert(value, type)
: value;
}
private Collection<String> getAliases(String key) {
Collection<String> names = new LinkedHashSet<>();
String value = getQualifier(key);
@@ -438,7 +392,7 @@ public class ContextFunctionCatalogAutoConfiguration {
private void wrap(FunctionRegistration<Object> registration, String key) {
Object target = registration.getTarget();
this.registrations.put(target, key);
this.names.put(target, key);
if (registration.getType() != null) {
this.types.put(key, registration.getType());
}
@@ -470,8 +424,8 @@ public class ContextFunctionCatalogAutoConfiguration {
else {
return;
}
this.registrations.remove(target);
this.registrations.put(registration.getTarget(), key);
this.names.remove(target);
this.names.put(registration.getTarget(), key);
if (publisher != null) {
publisher.publishEvent(new FunctionRegistrationEvent(
registration.getTarget(), type, registration.getNames()));
@@ -618,12 +572,8 @@ public class ContextFunctionCatalogAutoConfiguration {
return ReflectionUtils.getField(field, target);
}
private boolean isMessage(Object function) {
return findType(function).isMessage();
}
private FunctionType findType(Object function) {
String name = registrations.get(function);
String name = names.get(function);
if (types.containsKey(name)) {
return types.get(name);
}

View File

@@ -179,6 +179,12 @@ public class FunctionTypeTests {
assertThat(function).isSameAs(function.wrap(Flux.class));
}
@Test
public void nonWrapper() {
FunctionType function = FunctionType.from(Foo.class).to(Bar.class);
assertThat(function).isSameAs(function.wrap(Object.class));
}
private static class IntegerToString implements Function<Integer, String> {
@Override
public String apply(Integer t) {

View File

@@ -45,14 +45,15 @@ public class BeanFactoryFunctionCatalogTests {
@Test
public void basicRegistrationFeatures() {
processor.register(new FunctionRegistration<>(new Foos()).names("foos"));
Function<Flux<Integer>, Flux<String>> foos = processor.lookupFunction("foos");
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class,
"foos");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@Test
public void lookupFunctionWithEmptyName() {
processor.register(new FunctionRegistration<>(new Foos()).names("foos"));
Function<Flux<Integer>, Flux<String>> foos = processor.lookupFunction("");
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4");
}
@@ -61,7 +62,7 @@ public class BeanFactoryFunctionCatalogTests {
processor.register(new FunctionRegistration<Function<Integer, String>>(
(Integer i) -> "i=" + i).names("foos").type(
FunctionType.from(Integer.class).to(String.class).getType()));
Function<Flux<Integer>, Flux<String>> foos = processor.lookupFunction("");
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("i=2");
}
@@ -72,14 +73,14 @@ public class BeanFactoryFunctionCatalogTests {
ints -> ints.map(i -> "i=" + i)).names("foos")
.type(FunctionType.from(Integer.class).to(String.class)
.wrap(Flux.class).getType()));
Function<Flux<Integer>, Flux<String>> foos = processor.lookupFunction("");
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("i=2");
}
@Test
public void lookupNonExistentConsumerWithEmptyName() {
processor.register(new FunctionRegistration<>(new Foos()).names("foos"));
Consumer<Flux<String>> foos = processor.lookupConsumer("");
Consumer<Flux<String>> foos = processor.lookup(Consumer.class, "");
assertThat(foos).isNull();
}
@@ -87,8 +88,7 @@ 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
.lookupFunction("foos,bars");
Function<Flux<Integer>, Flux<String>> foos = processor.lookup(Function.class, "foos,bars");
assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4");
}
@@ -96,14 +96,14 @@ public class BeanFactoryFunctionCatalogTests {
public void composeSupplier() {
processor.register(new FunctionRegistration<>(new Source()).names("numbers"));
processor.register(new FunctionRegistration<>(new Foos()).names("foos"));
Supplier<Flux<String>> foos = processor.lookupSupplier("numbers,foos");
Supplier<Flux<String>> foos = processor.lookup(Supplier.class, "numbers,foos");
assertThat(foos.get().blockFirst()).isEqualTo("6");
}
@Test
public void composeUniqueSupplier() {
processor.register(new FunctionRegistration<>(new Source()).names("numbers"));
Supplier<Flux<Integer>> foos = processor.lookupSupplier("");
Supplier<Flux<Integer>> foos = processor.lookup(Supplier.class, "");
assertThat(foos.get().blockFirst()).isEqualTo(3);
}
@@ -112,7 +112,7 @@ 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.lookupConsumer("foos,sink");
Consumer<Flux<Integer>> foos = processor.lookup(Consumer.class, "foos,sink");
foos.accept(Flux.just(2));
assertThat(sink.values).contains("4");
}
@@ -121,7 +121,7 @@ public class BeanFactoryFunctionCatalogTests {
public void composeUniqueConsumer() {
Sink sink = new Sink();
processor.register(new FunctionRegistration<>(sink).names("sink"));
Consumer<Flux<String>> foos = processor.lookupConsumer("");
Consumer<Flux<String>> foos = processor.lookup(Consumer.class, "");
foos.accept(Flux.just("2"));
assertThat(sink.values).contains("2");
}

View File

@@ -90,30 +90,35 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void lookUps() {
create(SimpleConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(context.getBean("function2")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function,function2"))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = catalog
.lookupFunction("function,function2,function3");
assertThat(context.getBean("function2")).isInstanceOf(Function.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function,function2"))
.isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = catalog.lookup(Function.class,
"function,function2,function3");
assertThat(f).isInstanceOf(Function.class);
assertThat(f.apply(Flux.just("hello")).blockFirst())
.isEqualTo("HELLOfunction2function3");
assertThat(context.getBean("supplierFoo")).isInstanceOf(Supplier.class);
assertThat(catalog.lookupSupplier("supplierFoo")).isInstanceOf(Supplier.class);
assertThat(catalog.<Supplier<?>>lookup(Supplier.class, "supplierFoo"))
.isInstanceOf(Supplier.class);
assertThat(context.getBean("supplier_Foo")).isInstanceOf(Supplier.class);
assertThat(catalog.lookupSupplier("supplier_Foo")).isInstanceOf(Supplier.class);
assertThat(catalog.<Supplier<?>>lookup(Supplier.class, "supplier_Foo"))
.isInstanceOf(Supplier.class);
}
@Test
public void ambiguousFunction() {
create(AmbiguousConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("foos")).isInstanceOf(Function.class);
assertThat(catalog.lookupConsumer("foos")).isInstanceOf(Consumer.class);
assertThat(inspector.getInputType(catalog.lookupFunction("foos")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos"))
.isInstanceOf(Consumer.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(inspector.getInputType(catalog.lookupConsumer("foos")))
assertThat(inspector.getInputType(catalog.lookup(Consumer.class, "foos")))
.isEqualTo(Foo.class);
}
@@ -121,35 +126,38 @@ public class ContextFunctionCatalogAutoConfigurationTests {
@Test
public void composedFunction() {
create(MultipleConfiguration.class);
assertThat(catalog.lookupFunction("foos,bars")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("names,foos")).isNull();
assertThat(inspector.getInputType(catalog.lookupFunction("foos,bars")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos,bars"))
.isInstanceOf(Function.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "names,foos")).isNull();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos,bars")))
.isAssignableFrom(String.class);
assertThat(inspector.getOutputType(catalog.lookupFunction("foos,bars")))
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos,bars")))
.isAssignableFrom(Bar.class);
}
@Test
public void composedSupplier() {
create(MultipleConfiguration.class);
assertThat(catalog.lookupSupplier("names,foos")).isInstanceOf(Supplier.class);
assertThat(catalog.lookupFunction("names,foos")).isNull();
assertThat(inspector.getOutputType(catalog.lookupSupplier("names,foos")))
assertThat(catalog.<Supplier<?>>lookup(Supplier.class, "names,foos"))
.isInstanceOf(Supplier.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "names,foos")).isNull();
assertThat(inspector.getOutputType(catalog.lookup(Supplier.class, "names,foos")))
.isAssignableFrom(Foo.class);
// The input type is the same as the input type of the first element in the chain
assertThat(inspector.getInputType(catalog.lookupSupplier("names,foos")))
assertThat(inspector.getInputType(catalog.lookup(Supplier.class, "names,foos")))
.isAssignableFrom(Void.class);
}
@Test
public void composedConsumer() {
create(MultipleConfiguration.class);
assertThat(catalog.lookupConsumer("foos,print")).isInstanceOf(Consumer.class);
assertThat(catalog.lookupFunction("foos,print")).isNull();
assertThat(inspector.getInputType(catalog.lookupConsumer("foos,print")))
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")))
.isAssignableFrom(String.class);
// The output type is the same as the output type of the last element in the chain
assertThat(inspector.getOutputType(catalog.lookupConsumer("foos,print")))
assertThat(inspector.getOutputType(catalog.lookup(Consumer.class, "foos,print")))
.isAssignableFrom(Void.class);
}
@@ -157,10 +165,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void genericFunction() {
create(GenericConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@@ -168,11 +177,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void fluxMessageFunction() {
create(FluxMessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookupFunction("function"))).isTrue();
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
}
@@ -180,11 +191,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void publisherMessageFunction() {
create(PublisherMessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookupFunction("function"))).isTrue();
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Publisher.class);
}
@@ -192,11 +205,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void messageFunction() {
create(MessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookupFunction("function"))).isTrue();
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(String.class);
}
@@ -204,10 +219,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void genericFluxFunction() {
create(GenericFluxConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Flux.class);
}
@@ -215,10 +231,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void externalFunction() {
create(ExternalConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@@ -226,10 +243,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void singletonFunction() {
create(SingletonConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
}
@@ -237,22 +255,25 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void singletonMessageFunction() {
create(SingletonMessageConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.isMessage(catalog.lookupFunction("function"))).isTrue();
assertThat(inspector.isMessage(catalog.lookup(Function.class, "function")))
.isTrue();
}
@Test
public void nonParametericTypeFunction() {
create(NonParametricTypeSingletonConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Integer.class);
}
@@ -260,10 +281,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void componentScanBeanFunction() {
create(ComponentScanBeanConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@@ -271,10 +293,11 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void componentScanFunction() {
create(ComponentScanConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("function")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("function")))
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function")))
.isAssignableFrom(Map.class);
}
@@ -283,11 +306,13 @@ public class ContextFunctionCatalogAutoConfigurationTests {
try {
create("greeter.jar", ComponentScanJarConfiguration.class);
assertThat(context.getBean("greeter")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("greeter")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("greeter")))
.isAssignableFrom(String.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("greeter")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "greeter"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "greeter")))
.isAssignableFrom(String.class);
assertThat(
inspector.getInputWrapper(catalog.lookup(Function.class, "greeter")))
.isAssignableFrom(String.class);
}
finally {
ClassUtils.overrideThreadContextClassLoader(getClass().getClassLoader());
@@ -310,7 +335,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void simpleSupplier() {
create(SimpleConfiguration.class);
assertThat(context.getBean("supplier")).isInstanceOf(Supplier.class);
Supplier<Flux<String>> supplier = catalog.lookupSupplier("supplier");
Supplier<Flux<String>> supplier = catalog.lookup(Supplier.class, "supplier");
assertThat(supplier.get().blockFirst()).isEqualTo("hello");
}
@@ -318,7 +343,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void simpleConsumer() {
create(SimpleConfiguration.class);
assertThat(context.getBean("consumer")).isInstanceOf(Consumer.class);
Consumer<Flux<String>> consumer = catalog.lookupConsumer("consumer");
Consumer<Flux<String>> consumer = catalog.lookup(Consumer.class, "consumer");
consumer.accept(Flux.just("foo", "bar"));
assertThat(context.getBean(SimpleConfiguration.class).list).hasSize(2);
}
@@ -327,9 +352,10 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void qualifiedBean() {
create(QualifiedConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isNull();
assertThat(catalog.lookupFunction("other")).isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookupFunction("other")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function")).isNull();
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "other"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "other")))
.isEqualTo(String.class);
}
@@ -337,17 +363,21 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void aliasBean() {
create(AliasConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isNotNull();
assertThat(catalog.lookupFunction("other")).isInstanceOf(Function.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isNotNull();
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "other"))
.isInstanceOf(Function.class);
}
@Test
public void registrationBean() {
create(RegistrationConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("function")).isNull();
assertThat(catalog.lookupFunction("registration")).isNull();
assertThat(catalog.lookupFunction("other")).isInstanceOf(Function.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function")).isNull();
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "registration"))
.isNull();
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "other"))
.isInstanceOf(Function.class);
}
@Test
@@ -357,8 +387,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
"spring.cloud.function.compile.foos.inputType=String",
"spring.cloud.function.compile.foos.outputType=String");
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("foos")).isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("foos")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@@ -372,8 +403,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
create(EmptyConfiguration.class,
"spring.cloud.function.import.foos.location=file:./target/foos.fun");
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat(catalog.lookupFunction("foos")).isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookupFunction("foos")))
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@@ -384,8 +416,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
+ "::set",
"spring.cloud.function.compile.foos.type=consumer",
"spring.cloud.function.compile.foos.inputType=String");
assertThat(catalog.lookupConsumer("foos")).isInstanceOf(Consumer.class);
assertThat(inspector.getInputWrapper(catalog.lookupConsumer("foos")))
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos"))
.isInstanceOf(Consumer.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Consumer.class, "foos")))
.isEqualTo(String.class);
@SuppressWarnings("unchecked")
Consumer<String> consumer = (Consumer<String>) context.getBean("foos");
@@ -399,8 +432,9 @@ public class ContextFunctionCatalogAutoConfigurationTests {
"spring.cloud.function.compile.foos.lambda=f -> f.subscribe("
+ getClass().getName() + "::set)",
"spring.cloud.function.compile.foos.type=consumer");
assertThat(catalog.lookupConsumer("foos")).isInstanceOf(Consumer.class);
assertThat(inspector.getInputWrapper(catalog.lookupConsumer("foos")))
assertThat(catalog.<Consumer<?>>lookup(Consumer.class, "foos"))
.isInstanceOf(Consumer.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Consumer.class, "foos")))
.isEqualTo(Flux.class);
@SuppressWarnings("unchecked")
Consumer<Flux<String>> consumer = (Consumer<Flux<String>>) context
@@ -413,8 +447,10 @@ public class ContextFunctionCatalogAutoConfigurationTests {
public void factoryBeanFunction() {
create(FactoryBeanConfiguration.class);
assertThat(this.context.getBean("function")).isInstanceOf(Function.class);
assertThat(this.catalog.lookupFunction("function")).isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = this.catalog.lookupFunction("function");
assertThat(this.catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
Function<Flux<String>, Flux<String>> f = this.catalog.lookup(Function.class,
"function");
assertThat(f.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO-bar");
}