More cleanup and simplification in AbstractComposableFunctionRegistry
- We now rely on single map (no consumers, suppliers) - Simplified FunctionCreatorConfiguration to map FunctionType between class loaders
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.function.context;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
@@ -29,6 +30,7 @@ import reactor.core.publisher.Flux;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -66,6 +68,37 @@ public class FunctionType {
|
||||
this.message = messageType();
|
||||
}
|
||||
|
||||
/*
|
||||
* Experimental for now. Used (reflectively) in FunctionCreatorConfiguration to effectively
|
||||
* map an existing FunctionType created by one class loader to another.
|
||||
*/
|
||||
@SuppressWarnings("unused") // it is used
|
||||
private FunctionType(Object functionType) throws Exception {
|
||||
Field field = ReflectionUtils.findField(functionType.getClass(), "type");
|
||||
field.setAccessible(true);
|
||||
this.type = (Type) field.get(functionType);
|
||||
|
||||
field = ReflectionUtils.findField(functionType.getClass(), "inputWrapper");
|
||||
field.setAccessible(true);
|
||||
this.inputWrapper = (Class<?>) field.get(functionType);
|
||||
|
||||
field = ReflectionUtils.findField(functionType.getClass(), "outputWrapper");
|
||||
field.setAccessible(true);
|
||||
this.outputWrapper = (Class<?>) field.get(functionType);
|
||||
|
||||
field = ReflectionUtils.findField(functionType.getClass(), "inputType");
|
||||
field.setAccessible(true);
|
||||
this.inputType = (Class<?>) field.get(functionType);
|
||||
|
||||
field = ReflectionUtils.findField(functionType.getClass(), "outputType");
|
||||
field.setAccessible(true);
|
||||
this.outputType = (Class<?>) field.get(functionType);
|
||||
|
||||
field = ReflectionUtils.findField(functionType.getClass(), "message");
|
||||
field.setAccessible(true);
|
||||
this.message = (boolean) field.get(functionType);
|
||||
}
|
||||
|
||||
public static boolean isWrapper(Type type) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
type = ((ParameterizedType) type).getRawType();
|
||||
|
||||
@@ -67,8 +67,6 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class AbstractComposableFunctionRegistry implements FunctionRegistry,
|
||||
FunctionInspector, ApplicationEventPublisherAware, EnvironmentAware {
|
||||
|
||||
private final Map<String, Object> suppliers = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<String, Object> functions = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<Object, String> names = new ConcurrentHashMap<>();
|
||||
@@ -113,7 +111,10 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
||||
* @return immutable {@link Set} of available {@link Supplier} names.
|
||||
*/
|
||||
public Set<String> getSupplierNames() {
|
||||
return this.suppliers.keySet();
|
||||
return this.functions.entrySet().stream()
|
||||
.filter(entry -> entry.getValue() instanceof Supplier)
|
||||
.map(entry -> entry.getKey())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +122,10 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
||||
* @return immutable {@link Set} of available {@link Function} names.
|
||||
*/
|
||||
public Set<String> getFunctionNames() {
|
||||
return this.functions.keySet();
|
||||
return this.functions.entrySet().stream()
|
||||
.filter(entry -> !(entry.getValue() instanceof Supplier))
|
||||
.map(entry -> entry.getKey())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public boolean hasSuppliers() {
|
||||
@@ -140,7 +144,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return getSupplierNames().size() + getFunctionNames().size();
|
||||
return this.functions.size();
|
||||
}
|
||||
|
||||
public FunctionType getFunctionType(String name) {
|
||||
@@ -243,7 +247,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
||||
|
||||
|
||||
protected void addSupplier(String name, Supplier<?> supplier) {
|
||||
this.suppliers.put(name, supplier);
|
||||
this.functions.put(name, supplier);
|
||||
}
|
||||
|
||||
protected void addFunction(String name, Function<?, ?> function) {
|
||||
@@ -325,16 +329,16 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
||||
}
|
||||
|
||||
private FunctionRegistration<?> find(String name, boolean supplierFound) {
|
||||
Object result = this.suppliers.get(name);
|
||||
if (result == null) {
|
||||
result = this.functions.get(name);
|
||||
}
|
||||
Object result = this.functions.get(name);
|
||||
// if (result == null) {
|
||||
// result = this.functions.get(name);
|
||||
// }
|
||||
if (result == null && !StringUtils.hasText(name)) {
|
||||
if (supplierFound && this.functions.size() == 1) {
|
||||
result = this.functions.values().iterator().next();
|
||||
if (supplierFound && this.getFunctionNames().size() == 1) {
|
||||
result = this.functions.get(this.getFunctionNames().iterator().next());
|
||||
}
|
||||
else if (!supplierFound && this.suppliers.size() == 1) {
|
||||
result = this.suppliers.values().iterator().next();
|
||||
else if (!supplierFound && this.getSupplierNames().size() == 1) {
|
||||
result = this.functions.get(this.getSupplierNames().iterator().next());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,24 +430,9 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
||||
}
|
||||
|
||||
private Object doLookup(Class<?> type, String name) {
|
||||
Object function = null;
|
||||
if (type == null) {
|
||||
function = this.compose(name, this.functions);
|
||||
if (function == null) {
|
||||
function = this.compose(name, this.suppliers);
|
||||
}
|
||||
}
|
||||
else if (Function.class.isAssignableFrom(type)) {
|
||||
Object composed = this.compose(name, this.functions);
|
||||
if (composed != null && Function.class.isAssignableFrom(composed.getClass())) {
|
||||
function = composed;
|
||||
}
|
||||
}
|
||||
else if (Supplier.class.isAssignableFrom(type)) {
|
||||
Object composed = this.compose(name, this.suppliers);
|
||||
if (composed != null && Supplier.class.isAssignableFrom(composed.getClass())) {
|
||||
function = composed;
|
||||
}
|
||||
Object function = this.compose(name, this.functions);
|
||||
if (function != null && type != null && !type.isAssignableFrom(function.getClass())) {
|
||||
function = null;
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.cloud.function.deployer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
@@ -574,6 +575,26 @@ class FunctionCreatorConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private FunctionType createFunctionType(Object functionCatalog) {
|
||||
FunctionType functionType = null;
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
String name = ((Set<String>) this.runner.evaluate("getNames(#type)", functionCatalog, "type", null))
|
||||
.stream().findFirst().orElse(null);
|
||||
if (name != null) {
|
||||
Object ft = this.runner.evaluate("getFunctionType(#name)", functionCatalog, "name", name);
|
||||
Constructor<FunctionType> ftConstructor = FunctionType.class.getDeclaredConstructor(Object.class);
|
||||
ftConstructor.setAccessible(true);
|
||||
functionType = ftConstructor.newInstance(ft);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to extract and map FunctionType", e);
|
||||
|
||||
}
|
||||
return functionType;
|
||||
}
|
||||
|
||||
public void register(Object bean) {
|
||||
if (bean == null) {
|
||||
return;
|
||||
@@ -583,27 +604,34 @@ class FunctionCreatorConfiguration {
|
||||
FunctionProperties.functionName(this.counter.getAndIncrement()));
|
||||
if (this.runner != null) {
|
||||
if (this.runner.containsBean(FunctionInspector.class.getName())) {
|
||||
Object inspector = this.runner
|
||||
Object functionCatalog = this.runner
|
||||
.getBean(FunctionInspector.class.getName());
|
||||
Class<?> input = (Class<?>) this.runner.evaluate(
|
||||
"getInputType(#function)", inspector, "function", bean);
|
||||
FunctionType type = FunctionType.from(input);
|
||||
Class<?> output = findType("getOutputType", inspector, bean);
|
||||
type = type.to(output);
|
||||
if (((Boolean) this.runner.evaluate("isMessage(#function)", inspector,
|
||||
"function", bean))) {
|
||||
type = type.message();
|
||||
|
||||
FunctionType type = this.createFunctionType(functionCatalog);
|
||||
if (type == null) {
|
||||
Class<?> input = (Class<?>) this.runner.evaluate(
|
||||
"getInputType(#function)", functionCatalog, "function", bean);
|
||||
type = FunctionType.from(input);
|
||||
Class<?> output = findType("getOutputType", functionCatalog, bean);
|
||||
type = type.to(output);
|
||||
if (((Boolean) this.runner.evaluate("isMessage(#function)", functionCatalog,
|
||||
"function", bean))) {
|
||||
type = type.message();
|
||||
}
|
||||
Class<?> inputWrapper = findType("getInputWrapper", functionCatalog, bean);
|
||||
if (FunctionType.isWrapper(inputWrapper)) {
|
||||
type = type.wrap(inputWrapper);
|
||||
}
|
||||
Class<?> outputWrapper = findType("getOutputWrapper", functionCatalog,
|
||||
bean);
|
||||
if (FunctionType.isWrapper(outputWrapper)) {
|
||||
type = type.wrap(outputWrapper);
|
||||
}
|
||||
}
|
||||
Class<?> inputWrapper = findType("getInputWrapper", inspector, bean);
|
||||
if (FunctionType.isWrapper(inputWrapper)) {
|
||||
type = type.wrap(inputWrapper);
|
||||
}
|
||||
Class<?> outputWrapper = findType("getOutputWrapper", inspector,
|
||||
bean);
|
||||
if (FunctionType.isWrapper(outputWrapper)) {
|
||||
type = type.wrap(outputWrapper);
|
||||
}
|
||||
registration.type(type.getType());
|
||||
registration.type(this.createFunctionType(functionCatalog));
|
||||
|
||||
|
||||
//registration.type(type.getType());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user