Removed FunctionCatalog, BeanFactoryFunctionCatalogTests, ContextFunctionPostProcessorTests

Deprecated FluxWrapperDetector
Clean up and polishing of new BeanFactoryAwareFunctionRegistry
This commit is contained in:
Oleg Zhurakousky
2019-07-29 15:54:59 +02:00
parent cc5c522a8a
commit 90c69368c2
6 changed files with 63 additions and 831 deletions

View File

@@ -32,7 +32,6 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
@@ -44,7 +43,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.cloud.function.context.AbstractSpringFunctionAdapterInitializer;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.FunctionRegistration;
@@ -165,8 +163,33 @@ public class BeanFactoryAwareFunctionRegistry
return function;
}
private Type discoverFunctionType(Object function, String... names) {
boolean beanDefinitionExists = false;
for (int i = 0; i < names.length && !beanDefinitionExists; i++) {
beanDefinitionExists = this.applicationContext.getBeanFactory().containsBeanDefinition(names[i]);
}
return beanDefinitionExists
? FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), names)).getType()
: new FunctionType(function.getClass()).getType();
}
private String discoverDefaultDefinitionIfNecessary(String definition) {
if (StringUtils.isEmpty(definition)) {
String[] functionNames = this.applicationContext.getBeanNamesForType(Function.class);
if (!ObjectUtils.isEmpty(functionNames)) {
Assert.isTrue(functionNames.length == 1, "Found more then one function in BeanFactory");
definition = functionNames[0];
}
}
return definition;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Function<?, ?> compose(Class<?> type, String definition, String... acceptedOutputTypes) {
definition = discoverDefaultDefinitionIfNecessary(definition);
if (StringUtils.isEmpty(definition)) {
return null;
}
Function<?, ?> resultFunction = null;
if (this.registrationsByName.containsKey(definition)) {
Object targetFunction = this.registrationsByName.get(definition).getTarget();
@@ -174,65 +197,55 @@ public class BeanFactoryAwareFunctionRegistry
resultFunction = new FunctionInvocationWrapper(targetFunction, functionType, definition, acceptedOutputTypes);
}
else {
if (StringUtils.isEmpty(definition)) {
String[] functionNames = this.applicationContext.getBeanNamesForType(Function.class);
if (ObjectUtils.isEmpty(functionNames)) {
return null;
}
Assert.isTrue(functionNames.length == 1, "Found more then one function in BeanFactory");
definition = functionNames[0];
}
String[] names = StringUtils.delimitedListToStringArray(definition.replaceAll(",", "|").trim(), "|");
StringBuilder composedNameBuilder = new StringBuilder();
String prefix = "";
Type composedFunctionType = null;
Type originFunctionType = null;
for (String name : names) {
Object function = this.locateFunction(name);
if (function == null) {
return null;
}
if (composedFunctionType == null) {
composedFunctionType = beanDefinitionExists(name)
? FunctionType.of(FunctionContextUtils.findType(
(ConfigurableListableBeanFactory) applicationContext.getBeanFactory(), name)).getType()
: new FunctionType(function.getClass()).getType();
}
composedNameBuilder.append(prefix);
composedNameBuilder.append(name);
FunctionRegistration<Object> registration;
Type functionType = null;
Type currentFunctionType = null;
if (function instanceof FunctionRegistration) {
registration = (FunctionRegistration<Object>) function;
functionType = registration.getType().getType();
currentFunctionType = registration.getType().getType();
function = registration.getTarget();
}
else {
String[] aliasNames = this.getAliases(name).toArray(new String[] {});
functionType = beanDefinitionExists(aliasNames)
? FunctionType.of(FunctionContextUtils.findType(
(ConfigurableListableBeanFactory) applicationContext.getBeanFactory(), aliasNames)).getType()
: new FunctionType(function.getClass()).getType();
registration = new FunctionRegistration<>(function, name).type(functionType);
currentFunctionType = this.discoverFunctionType(function, aliasNames);
registration = new FunctionRegistration<>(function, name).type(currentFunctionType);
}
registrationsByFunction.putIfAbsent(function, registration);
registrationsByName.putIfAbsent(name, registration);
function = new FunctionInvocationWrapper(function, functionType, composedNameBuilder.toString(), acceptedOutputTypes);
function = new FunctionInvocationWrapper(function, currentFunctionType, name, acceptedOutputTypes);
if (originFunctionType == null) {
originFunctionType = currentFunctionType;
}
// composition
if (resultFunction == null) {
resultFunction = (Function<?, ?>) function;
}
else {
composedFunctionType = FunctionTypeUtils.compose(composedFunctionType, functionType);
originFunctionType = FunctionTypeUtils.compose(originFunctionType, currentFunctionType);
resultFunction = new FunctionInvocationWrapper(resultFunction.andThen((Function) function),
composedFunctionType, composedNameBuilder.toString(), acceptedOutputTypes);
registration = new FunctionRegistration<Object>(resultFunction, composedNameBuilder.toString())
.type(composedFunctionType);
registrationsByFunction.putIfAbsent(resultFunction, registration);
registrationsByName.putIfAbsent(composedNameBuilder.toString(), registration);
originFunctionType, composedNameBuilder.toString(), acceptedOutputTypes);
}
prefix = "|";
}
FunctionRegistration<Object> registration = new FunctionRegistration<Object>(resultFunction, definition)
.type(originFunctionType);
registrationsByFunction.putIfAbsent(resultFunction, registration);
registrationsByName.putIfAbsent(definition, registration);
}
return resultFunction;
}
@@ -263,15 +276,6 @@ public class BeanFactoryAwareFunctionRegistry
return key;
}
private boolean beanDefinitionExists(String... names) {
for (String name : names) {
if (this.applicationContext.getBeanFactory().containsBeanDefinition(name)) {
return true;
}
}
return false;
}
/**
* Single wrapper for all Suppliers, Functions and Consumers managed by this
* catalog.
@@ -285,7 +289,7 @@ public class BeanFactoryAwareFunctionRegistry
private final Type functionType;
private boolean composed;
private final boolean composed;
private final String[] acceptedOutputMimeTypes;
@@ -293,7 +297,6 @@ public class BeanFactoryAwareFunctionRegistry
FunctionInvocationWrapper(Object target, Type functionType, String functionDefinition, String... acceptedOutputMimeTypes) {
this.target = target;
this.composed = !target.getClass().getName().contains("EnhancerBySpringCGLIB") && target.getClass().getDeclaredFields().length > 1;
this.functionType = functionType;
this.acceptedOutputMimeTypes = acceptedOutputMimeTypes;
@@ -312,9 +315,9 @@ public class BeanFactoryAwareFunctionRegistry
@Override
public Object get() {
Object input = FunctionTypeUtils.isMono(functionType)
Object input = FunctionTypeUtils.isMono(this.functionType)
? Mono.empty()
: (FunctionTypeUtils.isMono(functionType) ? Flux.empty() : null);
: (FunctionTypeUtils.isMono(this.functionType) ? Flux.empty() : null);
return this.doApply(input, false);
}
@@ -337,7 +340,7 @@ public class BeanFactoryAwareFunctionRegistry
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object invokeFunction(Object input) {
if (target instanceof FunctionInvocationWrapper || target instanceof Function) {
if (target instanceof Function) {
return ((Function) target).apply(input);
}
else if (target instanceof Supplier) {
@@ -371,8 +374,9 @@ public class BeanFactoryAwareFunctionRegistry
}
else {
if (FunctionTypeUtils.isConsumer(functionType)) {
result = input instanceof Mono ? Mono.from((Publisher) input).doOnNext((Consumer) this.target).then()
: Flux.from((Publisher) input).doOnNext((Consumer) this.target).then();
result = input instanceof Mono
? Mono.from((Publisher) input).doOnNext((Consumer) this.target).then()
: Flux.from((Publisher) input).doOnNext((Consumer) this.target).then();
}
else {
result = input instanceof Mono
@@ -422,18 +426,12 @@ public class BeanFactoryAwareFunctionRegistry
}
else {
List<MimeType> acceptedContentTypes = MimeTypeUtils.parseMimeTypes(acceptedOutputMimeTypes[0].toString());
for (MimeType acceptedContentType : acceptedContentTypes) {
try {
MessageHeaders headers = new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, acceptedContentType));
convertedValue = messageConverter.toMessage(value, headers);
if (convertedValue != null) {
break;
}
}
catch (Exception e) {
// ignore
}
}
convertedValue = acceptedContentTypes.stream()
.map(acceptedContentType -> messageConverter
.toMessage(value, new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, acceptedContentType))))
.filter(v -> v != null)
.findFirst().orElse(null);
}
return convertedValue;

View File

@@ -218,7 +218,9 @@ public final class FunctionTypeUtils {
: (ObjectUtils.isEmpty(resolvableComposedType.getGenerics())
? ResolvableType.forClass(Object.class) : resolvableComposedType.getGenerics()[1]);
originType = ResolvableType.forClassWithGenerics(Function.class, resolvableOriginType.getGenerics()[0], outType).getType();
originType = ResolvableType.forClassWithGenerics(Function.class,
ObjectUtils.isEmpty(resolvableOriginType.getGenerics()) ? resolvableOriginType : resolvableOriginType.getGenerics()[0],
outType).getType();
}
return originType;
}

View File

@@ -16,59 +16,36 @@
package org.springframework.cloud.function.context.config;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.PreDestroy;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionRegistry;
import org.springframework.cloud.function.context.FunctionType;
import org.springframework.cloud.function.context.catalog.AbstractComposableFunctionRegistry;
import org.springframework.cloud.function.context.catalog.BeanFactoryAwareFunctionRegistry;
import org.springframework.cloud.function.context.catalog.FunctionInspector;
import org.springframework.cloud.function.context.catalog.FunctionUnregistrationEvent;
import org.springframework.cloud.function.json.GsonMapper;
import org.springframework.cloud.function.json.JacksonMapper;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.lang.Nullable;
import org.springframework.messaging.converter.ByteArrayMessageConverter;
import org.springframework.messaging.converter.CompositeMessageConverter;
@@ -127,144 +104,6 @@ public class ContextFunctionCatalogAutoConfiguration {
}
protected static class BeanFactoryFunctionCatalog extends AbstractComposableFunctionRegistry
implements SmartInitializingSingleton, BeanFactoryAware {
private ApplicationEventPublisher applicationEventPublisher;
private ConfigurableListableBeanFactory beanFactory;
/**
* Will collect all suppliers, functions, consumers and function registration as
* late as possible in the lifecycle.
*/
@SuppressWarnings("rawtypes")
@Override
public void afterSingletonsInstantiated() {
Map<String, Supplier> supplierBeans = this.beanFactory.getBeansOfType(Supplier.class);
Map<String, Function> functionBeans = this.beanFactory.getBeansOfType(Function.class);
Map<String, Consumer> consumerBeans = this.beanFactory.getBeansOfType(Consumer.class);
Map<String, FunctionRegistration> functionRegistrationBeans = this.beanFactory
.getBeansOfType(FunctionRegistration.class);
this.doMerge(functionRegistrationBeans, consumerBeans, supplierBeans, functionBeans);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@PreDestroy
public void close() {
if (this.applicationEventPublisher != null) {
if (this.hasFunctions()) {
this.applicationEventPublisher.publishEvent(
new FunctionUnregistrationEvent(this, Function.class, this.getFunctionNames()));
}
if (this.hasSuppliers()) {
this.applicationEventPublisher.publishEvent(
new FunctionUnregistrationEvent(this, Supplier.class, this.getSupplierNames()));
}
}
}
@Override
protected FunctionType findType(FunctionRegistration<?> functionRegistration, String name) {
FunctionType functionType = super.findType(functionRegistration, name);
if (functionType == null) {
functionType = functionByNameExist(name) ? new FunctionType(functionRegistration.getTarget().getClass())
: this.findType(name);
}
return functionType;
}
private FunctionType findType(String name) {
Type type = FunctionContextUtils.findType(name, this.beanFactory);
return type == null ? null : new FunctionType(type);
}
// @checkstyle:off
/**
* @param initial a registration
* @param consumers consumers to register
* @param suppliers suppliers to register
* @param functions functions to register
* @return a new registration
* @deprecated Was never intended for public use.
*/
@Deprecated
@SuppressWarnings("rawtypes")
Set<FunctionRegistration<?>> merge(Map<String, FunctionRegistration> initial, Map<String, Consumer> consumers,
Map<String, Supplier> suppliers, Map<String, Function> functions) {
this.doMerge(initial, consumers, suppliers, functions);
return null;
}
// @checkstyle:on
private Collection<String> getAliases(String key) {
Collection<String> names = new LinkedHashSet<>();
String value = getQualifier(key);
if (value.equals(key) && this.beanFactory != null) {
names.addAll(Arrays.asList(this.beanFactory.getAliases(key)));
}
names.add(value);
return names;
}
private String getQualifier(String key) {
if (this.beanFactory != null && this.beanFactory.containsBeanDefinition(key)) {
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition(key);
Object source = beanDefinition.getSource();
if (source instanceof StandardMethodMetadata) {
StandardMethodMetadata metadata = (StandardMethodMetadata) source;
Qualifier qualifier = AnnotatedElementUtils.findMergedAnnotation(metadata.getIntrospectedMethod(),
Qualifier.class);
if (qualifier != null && qualifier.value().length() > 0) {
return qualifier.value();
}
}
}
return key;
}
private boolean functionByNameExist(String name) {
return name == null || this.beanFactory == null || !this.beanFactory.containsBeanDefinition(name);
}
@SuppressWarnings("rawtypes")
private void doMerge(Map<String, FunctionRegistration> functionRegistrationBeans,
Map<String, Consumer> consumerBeans, Map<String, Supplier> supplierBeans,
Map<String, Function> functionBeans) {
Set<FunctionRegistration<?>> registrations = new HashSet<>();
Map<Object, String> targets = new HashMap<>();
// Replace the initial registrations with new ones that have the right names
for (String key : functionRegistrationBeans.keySet()) {
FunctionRegistration<?> registration = functionRegistrationBeans.get(key);
if (registration.getNames().isEmpty()) {
registration.names(getAliases(key));
}
registrations.add(registration);
targets.put(registration.getTarget(), key);
}
Stream.concat(consumerBeans.entrySet().stream(),
Stream.concat(supplierBeans.entrySet().stream(), functionBeans.entrySet().stream()))
.forEach(entry -> {
if (!targets.containsKey(entry.getValue())) {
FunctionRegistration<Object> target = new FunctionRegistration<Object>(entry.getValue(),
getAliases(entry.getKey()).toArray(new String[] {}));
targets.put(target.getTarget(), entry.getKey());
registrations.add(target);
}
});
registrations.forEach(registration -> register(registration, targets.get(registration.getTarget())));
}
}
private static class PreferGsonOrMissingJacksonCondition extends AnyNestedCondition {
PreferGsonOrMissingJacksonCondition() {

View File

@@ -24,8 +24,9 @@ import org.springframework.cloud.function.context.WrapperDetector;
/**
* @author Dave Syer
*
* @deprecated as of 3.0. Not used by the framework
*/
@Deprecated
public class FluxWrapperDetector implements WrapperDetector {
@Override