Fix Build and upgrade fully to Boot 2.0

Some tests still ignored.

Also adds draft functional bean registration support. The AWS sample
is using that now (it starts up 4x faster in AWS). To activate the
functional beans user has to supply a main class of type
ApplicationContextInitializer.
This commit is contained in:
Dave Syer
2018-06-21 13:00:46 +01:00
parent 00e2b749d2
commit 4c9627aee3
23 changed files with 896 additions and 54 deletions

View File

@@ -35,6 +35,16 @@ public class FunctionRegistrationTests {
assertThat(registration.getNames()).contains("foos");
}
@Test
public void wrap() {
FunctionRegistration<Foos> registration = new FunctionRegistration<>(new Foos())
.names("foos").type(FunctionType.of(Foos.class).getType());
FunctionRegistration<?> other = registration.wrap();
assertThat(registration.getType().isWrapper()).isFalse();
assertThat(other.getType().isWrapper()).isTrue();
assertThat(other.getTarget()).isNotEqualTo(registration.getTarget());
}
private static class Foos implements Function<Integer, String> {
@Override
public String apply(Integer t) {

View File

@@ -48,6 +48,26 @@ public class FunctionTypeTests {
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void supplierOfRegistration() {
FunctionType function = new FunctionType(SupplierOfRegistrationOfIntegerToString.class);
assertThat(function.getInputType()).isEqualTo(Integer.class);
assertThat(function.getOutputType()).isEqualTo(String.class);
assertThat(function.getInputWrapper()).isEqualTo(Integer.class);
assertThat(function.getOutputWrapper()).isEqualTo(String.class);
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void supplier() {
FunctionType function = new FunctionType(SupplierOfIntegerToString.class);
assertThat(function.getInputType()).isEqualTo(Integer.class);
assertThat(function.getOutputType()).isEqualTo(String.class);
assertThat(function.getInputWrapper()).isEqualTo(Integer.class);
assertThat(function.getOutputWrapper()).isEqualTo(String.class);
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void genericFunction() {
FunctionType function = new FunctionType(StringToMap.class);
@@ -125,6 +145,36 @@ public class FunctionTypeTests {
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void pojoSupplierFrom() {
FunctionType function = new FunctionType(Supplier.class).to(Foo.class);
assertThat(function.getInputType()).isEqualTo(Void.class);
assertThat(function.getOutputType()).isEqualTo(Foo.class);
assertThat(function.getInputWrapper()).isEqualTo(Void.class);
assertThat(function.getOutputWrapper()).isEqualTo(Foo.class);
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void pojoSupplier() {
FunctionType function = FunctionType.supplier(Foo.class);
assertThat(function.getInputType()).isEqualTo(Void.class);
assertThat(function.getOutputType()).isEqualTo(Foo.class);
assertThat(function.getInputWrapper()).isEqualTo(Void.class);
assertThat(function.getOutputWrapper()).isEqualTo(Foo.class);
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void pojoConsumer() {
FunctionType function = FunctionType.consumer(Foo.class);
assertThat(function.getOutputType()).isEqualTo(Void.class);
assertThat(function.getInputType()).isEqualTo(Foo.class);
assertThat(function.getOutputWrapper()).isEqualTo(Void.class);
assertThat(function.getInputWrapper()).isEqualTo(Foo.class);
assertThat(function.isMessage()).isEqualTo(false);
}
@Test
public void plainFunctionFromApi() {
FunctionType function = FunctionType.from(Integer.class).to(String.class);
@@ -197,6 +247,20 @@ public class FunctionTypeTests {
assertThat(function).isSameAs(function.wrap(Object.class));
}
private static class SupplierOfRegistrationOfIntegerToString implements Supplier<FunctionRegistration<Function<Integer, String>>> {
@Override
public FunctionRegistration<Function<Integer, String>> get() {
return new FunctionRegistration<Function<Integer,String>>(new IntegerToString());
}
}
private static class SupplierOfIntegerToString implements Supplier<Function<Integer, String>> {
@Override
public Function<Integer, String> get() {
return new IntegerToString();
}
}
private static class IntegerToString implements Function<Integer, String> {
@Override
public String apply(Integer t) {

View File

@@ -0,0 +1,281 @@
/*
* Copyright 2017 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
*
* http://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.context.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionType;
import org.springframework.cloud.function.context.catalog.FunctionInspector;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.GenericApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Dave Syert
*
*/
public class ContextFunctionCatalogBeanRegistrarTests {
private GenericApplicationContext context;
private FunctionCatalog catalog;
private FunctionInspector inspector;
@After
public void close() {
if (context != null) {
context.close();
}
}
@Test
public void lookUps() {
create(SimpleConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
// TODO: support for function composition
}
@Test(expected=BeanCreationException.class)
public void missingType() {
create(MissingTypeConfiguration.class);
assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "function"))
.isInstanceOf(Function.class);
// TODO: support for type inference from functional bean regsitrations
}
@Test
public void configurationFunction() {
create(FunctionConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(Foo.class);
assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos")))
.isEqualTo(Flux.class);
}
@Test
public void dependencyInjection() {
create(DependencyInjectionConfiguration.class);
assertThat(context.getBean("foos")).isInstanceOf(FunctionRegistration.class);
assertThat(catalog.<Function<?, ?>>lookup(Function.class, "foos"))
.isInstanceOf(Function.class);
assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos")))
.isEqualTo(String.class);
}
@Test
public void simpleFunction() {
create(SimpleConfiguration.class);
Object bean = context.getBean("function");
assertThat(bean).isInstanceOf(FunctionRegistration.class);
Function<Flux<String>, Flux<String>> function = catalog.lookup(Function.class,
"function");
assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO");
assertThat(bean).isNotSameAs(function);
assertThat(inspector.getRegistration(function)).isNotNull();
assertThat(inspector.getRegistration(function).getType())
.isEqualTo(FunctionType.from(String.class).to(String.class).wrap(Flux.class));
}
@Test
public void simpleSupplier() {
create(SimpleConfiguration.class);
assertThat(context.getBean("supplier")).isInstanceOf(FunctionRegistration.class);
Supplier<Flux<String>> supplier = catalog.lookup(Supplier.class, "supplier");
assertThat(supplier.get().blockFirst()).isEqualTo("hello");
}
@Test
public void simpleConsumer() {
create(SimpleConfiguration.class);
assertThat(context.getBean("consumer")).isInstanceOf(FunctionRegistration.class);
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);
}
@SuppressWarnings("unchecked")
private void create(
Class<? extends ApplicationContextInitializer<GenericApplicationContext>> type,
String... props) {
create(Arrays.asList(BeanUtils.instantiateClass(type))
.toArray(new ApplicationContextInitializer[0]), props);
}
private void create(ApplicationContextInitializer<GenericApplicationContext>[] types,
String... props) {
context = new GenericApplicationContext();
for (ApplicationContextInitializer<GenericApplicationContext> type : types) {
type.initialize(context);
}
new ContextFunctionCatalogBeanRegistrar().register(context);
context.refresh();
catalog = context.getBean(FunctionCatalog.class);
inspector = context.getBean(FunctionInspector.class);
}
protected static class EmptyConfiguration
implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext applicationContext) {
}
}
protected static class MissingTypeConfiguration
implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext context) {
context.registerBean("function", FunctionRegistration.class,
() -> new FunctionRegistration<Function<String, String>>(function()));
}
@Bean
public Function<String, String> function() {
return value -> value.toUpperCase();
}
}
protected static class SimpleConfiguration
implements ApplicationContextInitializer<GenericApplicationContext> {
private List<String> list = new ArrayList<>();
@Override
public void initialize(GenericApplicationContext context) {
context.registerBean("function", FunctionRegistration.class,
() -> new FunctionRegistration<Function<String, String>>(function())
.type(FunctionType.from(String.class).to(String.class)
.getType()));
context.registerBean("supplier", FunctionRegistration.class,
() -> new FunctionRegistration<Supplier<String>>(supplier())
.type(FunctionType.supplier(String.class).getType()));
context.registerBean("consumer", FunctionRegistration.class,
() -> new FunctionRegistration<Consumer<String>>(consumer())
.type(FunctionType.consumer(String.class).getType()));
context.registerBean(SimpleConfiguration.class, () -> this);
}
@Bean
public Function<String, String> function() {
return value -> value.toUpperCase();
}
@Bean
public Supplier<String> supplier() {
return () -> "hello";
}
@Bean
public Consumer<String> consumer() {
return value -> list.add(value);
}
}
protected static class DependencyInjectionConfiguration
implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext context) {
context.registerBean(String.class, () -> value());
context.registerBean("foos", FunctionRegistration.class,
() -> new FunctionRegistration<Function<String, Foo>>(
foos(context.getBean(String.class)))
.type(FunctionType.from(String.class).to(Foo.class)
.getType()));
}
@Bean
public Function<String, Foo> foos(String foo) {
return value -> new Foo(foo + ": " + value.toUpperCase());
}
@Bean
public String value() {
return "Hello";
}
}
protected static class FunctionConfiguration
implements Function<Flux<String>, Flux<Foo>>,
ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext context) {
context.registerBean("foos", FunctionConfiguration.class, () -> this);
context.registerBean("function", FunctionRegistration.class,
() -> new FunctionRegistration<Function<Flux<String>, Flux<Foo>>>(
this).type(FunctionConfiguration.class).name("foos"));
}
@Override
public Flux<Foo> apply(Flux<String> flux) {
return flux.map(foo -> new Foo(value() + ": " + foo.toUpperCase()));
}
@Bean
public String value() {
return "Hello";
}
}
public static class Foo {
private String value;
public Foo(String value) {
this.value = value;
}
Foo() {
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}

View File

@@ -173,7 +173,7 @@ public class ContextFunctionPostProcessorTests {
((URLClassLoader) getClass().getClassLoader()).getURLs(),
getClass().getClassLoader().getParent());
return BeanUtils
.instantiate(ClassUtils.resolveClassName(type.getName(), classLoader));
.instantiateClass(ClassUtils.resolveClassName(type.getName(), classLoader));
}
public static class Foos implements Function<Integer, String> {