Enable JSON conversion for non-Flux functions
- use ProxyWrapper around a FluxConsumer as well making it consistent with the behaviour of Flux functions - Enable introspection for scanned beans - Fix failing tests by passing JSON string as input messages (marshalled form expected from the binder)
This commit is contained in:
committed by
Dave Syer
parent
d1cf9b47a4
commit
70dff6bb6b
@@ -32,6 +32,7 @@ import java.util.function.Function;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -39,9 +40,9 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.cloud.function.registry.FunctionCatalog;
|
import org.springframework.cloud.function.registry.FunctionCatalog;
|
||||||
@@ -53,13 +54,12 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
import org.springframework.core.type.StandardMethodMetadata;
|
import org.springframework.core.type.StandardMethodMetadata;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
@@ -209,7 +209,7 @@ public class ContextFunctionCatalogAutoConfiguration {
|
|||||||
else if (!isFluxSupplier(key, target)) {
|
else if (!isFluxSupplier(key, target)) {
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
FluxSupplier value = new FluxSupplier(target);
|
FluxSupplier value = new FluxSupplier(target);
|
||||||
return value;
|
return wrapSupplier(value, mapper, key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return target;
|
return target;
|
||||||
@@ -226,7 +226,7 @@ public class ContextFunctionCatalogAutoConfiguration {
|
|||||||
else if (!isFluxFunction(key, target)) {
|
else if (!isFluxFunction(key, target)) {
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
FluxFunction value = new FluxFunction(target);
|
FluxFunction value = new FluxFunction(target);
|
||||||
return value;
|
return wrapFunction(value, mapper, key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return target;
|
return target;
|
||||||
@@ -242,7 +242,7 @@ public class ContextFunctionCatalogAutoConfiguration {
|
|||||||
else if (!isFluxConsumer(key, target)) {
|
else if (!isFluxConsumer(key, target)) {
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
FluxConsumer value = new FluxConsumer(target);
|
FluxConsumer value = new FluxConsumer(target);
|
||||||
return value;
|
return wrapConsumer(value, mapper, key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return target;
|
return target;
|
||||||
@@ -367,16 +367,38 @@ public class ContextFunctionCatalogAutoConfiguration {
|
|||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> findType(RootBeanDefinition definition, int index) {
|
private Class<?> findType(AbstractBeanDefinition definition, int index) {
|
||||||
StandardMethodMetadata source = (StandardMethodMetadata) definition
|
Object source = definition.getSource();
|
||||||
.getSource();
|
|
||||||
Type param;
|
Type param;
|
||||||
if (source instanceof StandardMethodMetadata) {
|
if (source instanceof StandardMethodMetadata) {
|
||||||
ParameterizedType type;
|
ParameterizedType type;
|
||||||
type = (ParameterizedType) (source.getIntrospectedMethod()
|
type = (ParameterizedType) ((StandardMethodMetadata) source).getIntrospectedMethod()
|
||||||
.getGenericReturnType());
|
.getGenericReturnType();
|
||||||
type = (ParameterizedType) type.getActualTypeArguments()[index];
|
Type typeArgumentAtIndex = type.getActualTypeArguments()[index];
|
||||||
param = type.getActualTypeArguments()[0];
|
if (typeArgumentAtIndex instanceof ParameterizedType) {
|
||||||
|
param = ((ParameterizedType) typeArgumentAtIndex).getActualTypeArguments()[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
param = typeArgumentAtIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (source instanceof FileSystemResource) {
|
||||||
|
try {
|
||||||
|
Type type = ClassUtils.forName(definition.getBeanClassName(), null);
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
Type typeArgumentAtIndex = ((ParameterizedType)type).getActualTypeArguments()[index];
|
||||||
|
if (typeArgumentAtIndex instanceof ParameterizedType) {
|
||||||
|
param = ((ParameterizedType) typeArgumentAtIndex).getActualTypeArguments()[0];
|
||||||
|
} else {
|
||||||
|
param = typeArgumentAtIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
param = type;
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new IllegalStateException("Cannot instrospect bean: " + definition, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ResolvableType resolvable = (ResolvableType) getField(definition,
|
ResolvableType resolvable = (ResolvableType) getField(definition,
|
||||||
@@ -398,11 +420,11 @@ public class ContextFunctionCatalogAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> findType(String name) {
|
private Class<?> findType(String name) {
|
||||||
return findType((RootBeanDefinition) registry.getBeanDefinition(name), 0);
|
return findType((AbstractBeanDefinition) registry.getBeanDefinition(name), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> findOutputType(String name) {
|
private Class<?> findOutputType(String name) {
|
||||||
return findType((RootBeanDefinition) registry.getBeanDefinition(name), 1);
|
return findType((AbstractBeanDefinition) registry.getBeanDefinition(name), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class FluxPojoStreamingConsumerTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Consumer<Flux<String>> sinkConsumer(final List<String> sinkCollector) {
|
public Consumer<Flux<String>> sinkConsumer(final List<String> sinkCollector) {
|
||||||
return foos -> foos.doOnNext(s -> sinkCollector.add(s));
|
return foos -> foos.subscribe(s -> sinkCollector.add(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class FluxStreamingConsumerTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
sink.input().send(MessageBuilder.withPayload(new Foo("foo")).build());
|
sink.input().send(MessageBuilder.withPayload(new String("{\"name\":\"foo\"}")).build());
|
||||||
assertThat(sinkCollector).hasSize(1);
|
assertThat(sinkCollector).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class PojoStreamingConsumerTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
sink.input().send(MessageBuilder.withPayload(new Foo("foo")).build());
|
sink.input().send(MessageBuilder.withPayload(new String("{\"name\":\"foo\"}")).build());
|
||||||
assertThat(sinkCollector).hasSize(1);
|
assertThat(sinkCollector).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user