Compiler warnings and witespace

This commit is contained in:
Dave Syer
2018-09-17 13:37:51 +01:00
parent c964dc5451
commit b3ff7ab680
2 changed files with 536 additions and 520 deletions

View File

@@ -16,20 +16,12 @@
package org.springframework.cloud.function.context.config;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
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.concurrent.ConcurrentHashMap;
@@ -47,9 +39,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -66,7 +55,6 @@ import org.springframework.cloud.function.context.catalog.FunctionUnregistration
import org.springframework.cloud.function.core.FluxConsumer;
import org.springframework.cloud.function.core.FluxFunction;
import org.springframework.cloud.function.core.FluxSupplier;
import org.springframework.cloud.function.core.FunctionFactoryMetadata;
import org.springframework.cloud.function.core.IsolatedConsumer;
import org.springframework.cloud.function.core.IsolatedFunction;
import org.springframework.cloud.function.core.IsolatedSupplier;
@@ -76,15 +64,10 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.core.type.classreading.MethodMetadataReadingVisitor;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
@@ -98,470 +81,488 @@ import org.springframework.util.StringUtils;
@ConditionalOnMissingBean(FunctionCatalog.class)
public class ContextFunctionCatalogAutoConfiguration {
static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper";
static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper";
@Autowired(required = false)
private Map<String, Supplier<?>> suppliers = Collections.emptyMap();
@Autowired(required = false)
private Map<String, Supplier<?>> suppliers = Collections.emptyMap();
@Autowired(required = false)
private Map<String, Function<?, ?>> functions = Collections.emptyMap();
@Autowired(required = false)
private Map<String, Function<?, ?>> functions = Collections.emptyMap();
@Autowired(required = false)
private Map<String, Consumer<?>> consumers = Collections.emptyMap();
@Autowired(required = false)
private Map<String, Consumer<?>> consumers = Collections.emptyMap();
@Autowired(required = false)
private Map<String, FunctionRegistration<?>> registrations = Collections.emptyMap();
@Autowired(required = false)
private Map<String, FunctionRegistration<?>> registrations = Collections.emptyMap();
@Bean
public FunctionRegistry functionCatalog(ContextFunctionRegistry processor) {
processor.merge(registrations, consumers, suppliers, functions);
return new BeanFactoryFunctionCatalog(processor);
}
@Bean
public FunctionRegistry functionCatalog(ContextFunctionRegistry processor) {
processor.merge(registrations, consumers, suppliers, functions);
return new BeanFactoryFunctionCatalog(processor);
}
@Bean
public FunctionInspector functionInspector(ContextFunctionRegistry processor) {
return new BeanFactoryFunctionInspector(processor);
}
@Bean
public FunctionInspector functionInspector(ContextFunctionRegistry processor) {
return new BeanFactoryFunctionInspector(processor);
}
protected static class BeanFactoryFunctionCatalog implements FunctionRegistry {
protected static class BeanFactoryFunctionCatalog implements FunctionRegistry {
private final ContextFunctionRegistry processor;
private final ContextFunctionRegistry processor;
@Override
public <T> void register(FunctionRegistration<T> registration) {
Assert.notEmpty(registration.getNames(), "'registration' must contain at least one name before it is registered in catalog.");
processor.register(registration);
}
@Override
public <T> void register(FunctionRegistration<T> registration) {
Assert.notEmpty(registration.getNames(),
"'registration' must contain at least one name before it is registered in catalog.");
processor.register(registration);
}
@Override
@SuppressWarnings("unchecked")
public <T> T lookup(Class<T> type, String name) {
T function = null;
if (type == null) {
function = (T) processor.lookupFunction(name);
if (function == null) {
function = (T) processor.lookupConsumer(name);
}
if (function == null) {
function = (T) processor.lookupSupplier(name);
}
} else if (Supplier.class.isAssignableFrom(type)) {
function = (T) processor.lookupSupplier(name);
} else if (Consumer.class.isAssignableFrom(type)) {
function = (T) processor.lookupConsumer(name);
} else if (Function.class.isAssignableFrom(type)) {
function = (T) processor.lookupFunction(name);
}
return function;
}
@Override
@SuppressWarnings("unchecked")
public <T> T lookup(Class<T> type, String name) {
T function = null;
if (type == null) {
function = (T) processor.lookupFunction(name);
if (function == null) {
function = (T) processor.lookupConsumer(name);
}
if (function == null) {
function = (T) processor.lookupSupplier(name);
}
}
else if (Supplier.class.isAssignableFrom(type)) {
function = (T) processor.lookupSupplier(name);
}
else if (Consumer.class.isAssignableFrom(type)) {
function = (T) processor.lookupConsumer(name);
}
else if (Function.class.isAssignableFrom(type)) {
function = (T) processor.lookupFunction(name);
}
return function;
}
@Override
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();
}
@Override
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();
}
@Override
public int size() {
return this.processor.getSuppliers().size() +
this.processor.getFunctions().size() +
this.processor.getConsumers().size();
}
@Override
public int size() {
return this.processor.getSuppliers().size()
+ this.processor.getFunctions().size()
+ this.processor.getConsumers().size();
}
public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) {
this.processor = processor;
}
public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) {
this.processor = processor;
}
}
}
protected class BeanFactoryFunctionInspector implements FunctionInspector {
protected class BeanFactoryFunctionInspector implements FunctionInspector {
private ContextFunctionRegistry processor;
private ContextFunctionRegistry processor;
public BeanFactoryFunctionInspector(ContextFunctionRegistry processor) {
this.processor = processor;
}
public BeanFactoryFunctionInspector(ContextFunctionRegistry processor) {
this.processor = processor;
}
@Override
public FunctionRegistration<?> getRegistration(Object function) {
FunctionRegistration<?> registration = processor.getRegistration(function);
return registration;
}
@Override
public FunctionRegistration<?> getRegistration(Object function) {
FunctionRegistration<?> registration = processor.getRegistration(function);
return registration;
}
}
}
@Configuration
@ConditionalOnClass(Gson.class)
@ConditionalOnBean(Gson.class)
@Conditional(PreferGsonOrMissingJacksonCondition.class)
protected static class GsonConfiguration {
@Bean
public GsonMapper jsonMapper(Gson gson) {
return new GsonMapper(gson);
}
}
@Configuration
@ConditionalOnClass(Gson.class)
@ConditionalOnBean(Gson.class)
@Conditional(PreferGsonOrMissingJacksonCondition.class)
protected static class GsonConfiguration {
@Bean
public GsonMapper jsonMapper(Gson gson) {
return new GsonMapper(gson);
}
}
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
protected static class JacksonConfiguration {
@Bean
public JacksonMapper jsonMapper(ObjectMapper mapper) {
return new JacksonMapper(mapper);
}
}
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
protected static class JacksonConfiguration {
@Bean
public JacksonMapper jsonMapper(ObjectMapper mapper) {
return new JacksonMapper(mapper);
}
}
@Component
protected static class ContextFunctionRegistry {
@Component
protected static class ContextFunctionRegistry {
private Map<String, Object> suppliers = new ConcurrentHashMap<>();
private Map<String, Object> suppliers = new ConcurrentHashMap<>();
private Map<String, Object> functions = new ConcurrentHashMap<>();
private Map<String, Object> functions = new ConcurrentHashMap<>();
private Map<String, Object> consumers = new ConcurrentHashMap<>();
private Map<String, Object> consumers = new ConcurrentHashMap<>();
@Autowired(required = false)
private ApplicationEventPublisher publisher;
@Autowired(required = false)
private ApplicationEventPublisher publisher;
@Autowired
private ConfigurableListableBeanFactory registry;
@Autowired
private ConfigurableListableBeanFactory registry;
private Map<Object, String> names = new ConcurrentHashMap<>();
private Map<Object, String> names = new ConcurrentHashMap<>();
private Map<String, FunctionType> types = new ConcurrentHashMap<>();
private Map<String, FunctionType> types = new ConcurrentHashMap<>();
public Set<String> getSuppliers() {
return this.suppliers.keySet();
}
public Set<String> getSuppliers() {
return this.suppliers.keySet();
}
public FunctionRegistration<?> getRegistration(Object function) {
if (function == null || !names.containsKey(function)) {
return null;
}
return new FunctionRegistration<>(function, names.get(function))
.type(findType(function).getType());
}
public FunctionRegistration<?> getRegistration(Object function) {
if (function == null || !names.containsKey(function)) {
return null;
}
return new FunctionRegistration<>(function, names.get(function))
.type(findType(function).getType());
}
public Set<String> getConsumers() {
return this.consumers.keySet();
}
public Set<String> getConsumers() {
return this.consumers.keySet();
}
public Set<String> getFunctions() {
return this.functions.keySet();
}
public Set<String> getFunctions() {
return this.functions.keySet();
}
public Supplier<?> lookupSupplier(String name) {
Object composed = compose(name, this.suppliers, false);
if (composed instanceof Supplier) {
return (Supplier<?>) composed;
}
return null;
}
public Supplier<?> lookupSupplier(String name) {
Object composed = compose(name, this.suppliers, false);
if (composed instanceof Supplier) {
return (Supplier<?>) composed;
}
return null;
}
public Consumer<?> lookupConsumer(String name) {
Object composed = compose(name, this.consumers, true);
if (composed instanceof Consumer) {
return (Consumer<?>) composed;
}
return null;
}
public Consumer<?> lookupConsumer(String name) {
Object composed = compose(name, this.consumers, true);
if (composed instanceof Consumer) {
return (Consumer<?>) composed;
}
return null;
}
public Function<?, ?> lookupFunction(String name) {
Object composed = compose(name, this.functions, true);
if (composed instanceof Function) {
return (Function<?, ?>) composed;
}
return null;
}
public Function<?, ?> lookupFunction(String name) {
Object composed = compose(name, this.functions, true);
if (composed instanceof Function) {
return (Function<?, ?>) composed;
}
return null;
}
private Object compose(String name, Map<String, Object> lookup,
boolean hasInput) {
name = name.replaceAll(",", "|");
if (lookup.containsKey(name)) {
return lookup.get(name);
}
String[] stages = StringUtils.delimitedListToStringArray(name, "|");
Map<String, Object> source = !hasInput || stages.length <= 1 ? lookup
: this.functions;
if (stages.length == 0 && source.size() == 1) {
stages = new String[]{source.keySet().iterator().next()};
}
Object function = stages.length > 0 ? lookup(stages[0], source) : null;
if (function == null) {
return null;
}
Object other = null;
for (int i = 1; i < stages.length - 1; i++) {
other = lookup(stages[i], this.functions);
if (other == null) {
return null;
}
function = compose(function, other);
}
if (stages.length > 1) {
other = lookup(stages[stages.length - 1],
hasInput ? lookup : this.functions);
if (other == null) {
return null;
}
function = compose(function, other);
}
final Object value = function;
lookup.computeIfAbsent(name, key -> value);
if (!types.containsKey(name)) {
if (types.containsKey(stages[0])
&& types.containsKey(stages[stages.length - 1])) {
FunctionType input = types.get(stages[0]);
FunctionType output = types.get(stages[stages.length - 1]);
types.put(name, FunctionType.compose(input, output));
}
}
names.put(function, name);
return function;
}
private Object compose(String name, Map<String, Object> lookup,
boolean hasInput) {
name = name.replaceAll(",", "|");
if (lookup.containsKey(name)) {
return lookup.get(name);
}
String[] stages = StringUtils.delimitedListToStringArray(name, "|");
Map<String, Object> source = !hasInput || stages.length <= 1 ? lookup
: this.functions;
if (stages.length == 0 && source.size() == 1) {
stages = new String[] { source.keySet().iterator().next() };
}
Object function = stages.length > 0 ? lookup(stages[0], source) : null;
if (function == null) {
return null;
}
Object other = null;
for (int i = 1; i < stages.length - 1; i++) {
other = lookup(stages[i], this.functions);
if (other == null) {
return null;
}
function = compose(function, other);
}
if (stages.length > 1) {
other = lookup(stages[stages.length - 1],
hasInput ? lookup : this.functions);
if (other == null) {
return null;
}
function = compose(function, other);
}
final Object value = function;
lookup.computeIfAbsent(name, key -> value);
if (!types.containsKey(name)) {
if (types.containsKey(stages[0])
&& types.containsKey(stages[stages.length - 1])) {
FunctionType input = types.get(stages[0]);
FunctionType output = types.get(stages[stages.length - 1]);
types.put(name, FunctionType.compose(input, output));
}
}
names.put(function, name);
return function;
}
private Object lookup(String name, Map<String, Object> lookup) {
Object result = lookup.get(name);
if (result != null) {
findType(result);
}
return result;
}
private Object lookup(String name, Map<String, Object> lookup) {
Object result = lookup.get(name);
if (result != null) {
findType(result);
}
return result;
}
@SuppressWarnings("unchecked")
private Object compose(Object a, Object b) {
if (a instanceof Supplier && b instanceof Function) {
Supplier<Object> supplier = (Supplier<Object>) a;
Function<Object, Object> function = (Function<Object, Object>) b;
return (Supplier<Object>) () -> function.apply(supplier.get());
} else if (a instanceof Function && b instanceof Function) {
Function<Object, Object> function1 = (Function<Object, Object>) a;
Function<Object, Object> function2 = (Function<Object, Object>) b;
return function1.andThen(function2);
} else if (a instanceof Function && b instanceof Consumer) {
Function<Object, Object> function = (Function<Object, Object>) a;
Consumer<Object> consumer = (Consumer<Object>) b;
return (Consumer<Object>) v -> consumer.accept(function.apply(v));
} else {
throw new IllegalArgumentException(String.format(
"Could not compose %s and %s", a.getClass(), b.getClass()));
}
}
@SuppressWarnings("unchecked")
private Object compose(Object a, Object b) {
if (a instanceof Supplier && b instanceof Function) {
Supplier<Object> supplier = (Supplier<Object>) a;
Function<Object, Object> function = (Function<Object, Object>) b;
return (Supplier<Object>) () -> function.apply(supplier.get());
}
else if (a instanceof Function && b instanceof Function) {
Function<Object, Object> function1 = (Function<Object, Object>) a;
Function<Object, Object> function2 = (Function<Object, Object>) b;
return function1.andThen(function2);
}
else if (a instanceof Function && b instanceof Consumer) {
Function<Object, Object> function = (Function<Object, Object>) a;
Consumer<Object> consumer = (Consumer<Object>) b;
return (Consumer<Object>) v -> consumer.accept(function.apply(v));
}
else {
throw new IllegalArgumentException(String.format(
"Could not compose %s and %s", a.getClass(), b.getClass()));
}
}
@SuppressWarnings("unchecked")
public <T> void register(FunctionRegistration<T> function) {
wrap((FunctionRegistration<Object>) function,
function.getNames().iterator().next());
}
public <T> void register(FunctionRegistration<T> function) {
wrap(function, function.getNames().iterator().next());
}
@PreDestroy
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()));
}
}
}
@PreDestroy
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()));
}
}
}
public Set<FunctionRegistration<?>> merge(
Map<String, FunctionRegistration<?>> initial,
Map<String, Consumer<?>> consumers, Map<String, Supplier<?>> suppliers,
Map<String, Function<?, ?>> functions) {
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 : initial.keySet()) {
FunctionRegistration<?> registration = initial.get(key);
if (registration.getNames().isEmpty()) {
registration.names(getAliases(key));
}
registrations.add(registration);
targets.put(registration.getTarget(), key);
}
public Set<FunctionRegistration<?>> merge(
Map<String, FunctionRegistration<?>> initial,
Map<String, Consumer<?>> consumers, Map<String, Supplier<?>> suppliers,
Map<String, Function<?, ?>> functions) {
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 : initial.keySet()) {
FunctionRegistration<?> registration = initial.get(key);
if (registration.getNames().isEmpty()) {
registration.names(getAliases(key));
}
registrations.add(registration);
targets.put(registration.getTarget(), key);
}
Stream.concat(consumers.entrySet().stream(), Stream.concat(suppliers.entrySet().stream(), functions.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);
}
});
// Wrap the functions so they handle reactive inputs and outputs
registrations.forEach(registration -> wrap(registration, targets.get(registration.getTarget())));
return registrations;
}
Stream.concat(consumers.entrySet().stream(), Stream
.concat(suppliers.entrySet().stream(), functions.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);
}
});
// Wrap the functions so they handle reactive inputs and outputs
registrations.forEach(registration -> wrap(registration,
targets.get(registration.getTarget())));
return registrations;
}
private Collection<String> getAliases(String key) {
Collection<String> names = new LinkedHashSet<>();
String value = getQualifier(key);
if (value.equals(key) && registry != null) {
names.addAll(Arrays.asList(registry.getAliases(key)));
}
names.add(value);
return names;
}
private Collection<String> getAliases(String key) {
Collection<String> names = new LinkedHashSet<>();
String value = getQualifier(key);
if (value.equals(key) && registry != null) {
names.addAll(Arrays.asList(registry.getAliases(key)));
}
names.add(value);
return names;
}
private void wrap(FunctionRegistration<?> registration, String key) {
Object target = registration.getTarget();
this.names.put(target, key);
if (registration.getType() != null) {
this.types.put(key, registration.getType());
} else {
registration.type(findType(target).getType());
}
Class<?> type;
registration = transform(registration);
target = registration.getTarget();
if (target instanceof Supplier) {
type = Supplier.class;
for (String name : registration.getNames()) {
this.suppliers.put(name, registration.getTarget());
}
} else if (target instanceof Consumer) {
type = Consumer.class;
for (String name : registration.getNames()) {
this.consumers.put(name, registration.getTarget());
}
} else if (target instanceof Function) {
type = Function.class;
for (String name : registration.getNames()) {
this.functions.put(name, registration.getTarget());
}
} else {
return;
}
// this.names.remove(target);
this.names.put(registration.getTarget(), key);
if (publisher != null) {
publisher.publishEvent(new FunctionRegistrationEvent(
registration.getTarget(), type, registration.getNames()));
}
}
private void wrap(FunctionRegistration<?> registration, String key) {
Object target = registration.getTarget();
this.names.put(target, key);
if (registration.getType() != null) {
this.types.put(key, registration.getType());
}
else {
registration.type(findType(target).getType());
}
Class<?> type;
registration = transform(registration);
target = registration.getTarget();
if (target instanceof Supplier) {
type = Supplier.class;
for (String name : registration.getNames()) {
this.suppliers.put(name, registration.getTarget());
}
}
else if (target instanceof Consumer) {
type = Consumer.class;
for (String name : registration.getNames()) {
this.consumers.put(name, registration.getTarget());
}
}
else if (target instanceof Function) {
type = Function.class;
for (String name : registration.getNames()) {
this.functions.put(name, registration.getTarget());
}
}
else {
return;
}
// this.names.remove(target);
this.names.put(registration.getTarget(), key);
if (publisher != null) {
publisher.publishEvent(new FunctionRegistrationEvent(
registration.getTarget(), type, registration.getNames()));
}
}
private FunctionRegistration<?> transform(FunctionRegistration<?> registration) {
return fluxify(isolated(registration));
}
private FunctionRegistration<?> transform(FunctionRegistration<?> registration) {
return fluxify(isolated(registration));
}
@SuppressWarnings({"rawtypes", "unchecked"})
private FunctionRegistration<?> fluxify(FunctionRegistration<?> input) {
FunctionRegistration<Object> registration = (FunctionRegistration<Object>) input;
Object target = registration.getTarget();
FunctionType type = registration.getType();
boolean flux = hasFluxTypes(type);
if (!flux) {
if (target instanceof Supplier<?>) {
target = new FluxSupplier((Supplier<?>) target);
} else if (target instanceof Function<?, ?>) {
target = new FluxFunction((Function<?, ?>) target);
} else if (target instanceof Consumer<?>) {
target = new FluxConsumer((Consumer<?>) target);
}
registration.target(target);
}
return registration;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private FunctionRegistration<?> fluxify(FunctionRegistration<?> input) {
FunctionRegistration<Object> registration = (FunctionRegistration<Object>) input;
Object target = registration.getTarget();
FunctionType type = registration.getType();
boolean flux = hasFluxTypes(type);
if (!flux) {
if (target instanceof Supplier<?>) {
target = new FluxSupplier((Supplier<?>) target);
}
else if (target instanceof Function<?, ?>) {
target = new FluxFunction((Function<?, ?>) target);
}
else if (target instanceof Consumer<?>) {
target = new FluxConsumer((Consumer<?>) target);
}
registration.target(target);
}
return registration;
}
private boolean hasFluxTypes(FunctionType type) {
return type.isWrapper();
}
private boolean hasFluxTypes(FunctionType type) {
return type.isWrapper();
}
@SuppressWarnings({"rawtypes", "unchecked"})
private FunctionRegistration<?> isolated(FunctionRegistration<?> input) {
FunctionRegistration<Object> registration = (FunctionRegistration<Object>) input;
Object target = registration.getTarget();
boolean isolated = getClass().getClassLoader() != target.getClass()
.getClassLoader();
if (target instanceof Supplier<?>) {
if (isolated) {
target = new IsolatedSupplier((Supplier<?>) target);
}
} else if (target instanceof Function<?, ?>) {
if (isolated) {
target = new IsolatedFunction((Function<?, ?>) target);
}
} else if (target instanceof Consumer<?>) {
if (isolated) {
target = new IsolatedConsumer((Consumer<?>) target);
}
}
registration.target(target);
return registration;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private FunctionRegistration<?> isolated(FunctionRegistration<?> input) {
FunctionRegistration<Object> registration = (FunctionRegistration<Object>) input;
Object target = registration.getTarget();
boolean isolated = getClass().getClassLoader() != target.getClass()
.getClassLoader();
if (target instanceof Supplier<?>) {
if (isolated) {
target = new IsolatedSupplier((Supplier<?>) target);
}
}
else if (target instanceof Function<?, ?>) {
if (isolated) {
target = new IsolatedFunction((Function<?, ?>) target);
}
}
else if (target instanceof Consumer<?>) {
if (isolated) {
target = new IsolatedConsumer((Consumer<?>) target);
}
}
registration.target(target);
return registration;
}
private String getQualifier(String key) {
if (registry != null && registry.containsBeanDefinition(key)) {
BeanDefinition beanDefinition = registry.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 String getQualifier(String key) {
if (registry != null && registry.containsBeanDefinition(key)) {
BeanDefinition beanDefinition = registry.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 FunctionType findType(Object function) {
String name = names.get(function);
if (types.containsKey(name)) {
return types.get(name);
}
FunctionType param;
if (name == null || registry == null
|| !registry.containsBeanDefinition(name)) {
if (function != null) {
param = new FunctionType(function.getClass());
} else {
param = FunctionType.UNCLASSIFIED;
}
} else {
param = FunctionContextUtils.findType(name, registry);
}
types.computeIfAbsent(name, str -> param);
return param;
}
private FunctionType findType(Object function) {
String name = names.get(function);
if (types.containsKey(name)) {
return types.get(name);
}
FunctionType param;
if (name == null || registry == null
|| !registry.containsBeanDefinition(name)) {
if (function != null) {
param = new FunctionType(function.getClass());
}
else {
param = FunctionType.UNCLASSIFIED;
}
}
else {
param = FunctionContextUtils.findType(name, registry);
}
types.computeIfAbsent(name, str -> param);
return param;
}
}
}
private static class PreferGsonOrMissingJacksonCondition extends AnyNestedCondition {
private static class PreferGsonOrMissingJacksonCondition extends AnyNestedCondition {
PreferGsonOrMissingJacksonCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
PreferGsonOrMissingJacksonCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false)
static class GsonPreferred {
@ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false)
static class GsonPreferred {
}
}
@ConditionalOnMissingBean(ObjectMapper.class)
static class JacksonMissing {
@ConditionalOnMissingBean(ObjectMapper.class)
static class JacksonMissing {
}
}
}
}
}

View File

@@ -16,11 +16,13 @@
package org.springframework.cloud.function.context.config;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -31,127 +33,140 @@ import org.springframework.cloud.function.context.FunctionType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
/**
* Configuration class which defines the required infrastructure to
* bootstrap Kotlin lambdas as invocable functions within the context of the framework.
* Configuration class which defines the required infrastructure to bootstrap Kotlin
* lambdas as invocable functions within the context of the framework.
*
* @author Oleg Zhurakousky
*
* @since 2.0
*/
@Configuration
@ConditionalOnClass(name="kotlin.jvm.functions.Function1")
@ConditionalOnClass(name = "kotlin.jvm.functions.Function1")
class KotlinLambdaToFunctionAutoConfiguration implements BeanFactoryAware {
protected final Log logger = LogFactory.getLog(getClass());
protected final Log logger = LogFactory.getLog(getClass());
private ConfigurableListableBeanFactory beanFactory;
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
/**
* Will transform all discovered Kotlin's Function1 and Function0 lambdas to
* java Supplier, Function and Consumer, retaining the original Kotlin type characteristics.
* In other words the resulting bean coudl be cast to both java and kotlin
* types (i.e., java Function<I,O> vs. kotlin Function1<I,O>)
*/
@Bean
public BeanPostProcessor kotlinPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Function1) {
FunctionType functionType = FunctionContextUtils.findType(beanName, beanFactory);
if (Unit.class.isAssignableFrom(functionType.getOutputType())) {
logger.debug("Transforming Kotlin lambda " + beanName + " to java Consumer");
bean = new KotlinConsumer((Function1) bean);
}
else {
logger.debug("Transforming Kotlin lambda " + beanName + " to java Function");
bean = new KotlinFunction((Function1) bean);
}
}
else if (bean instanceof Function0) {
logger.debug("Transforming Kotlin lambda " + beanName + " to java Supplier");
bean = new KotlinSupplier((Function0) bean);
}
return bean;
}
};
}
/**
* Will transform all discovered Kotlin's Function1 and Function0 lambdas to java
* Supplier, Function and Consumer, retaining the original Kotlin type
* characteristics. In other words the resulting bean coudl be cast to both java and
* kotlin types (i.e., java Function<I,O> vs. kotlin Function1<I,O>)
*/
@Bean
public BeanPostProcessor kotlinPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof Function1) {
FunctionType functionType = FunctionContextUtils.findType(beanName,
beanFactory);
if (Unit.class.isAssignableFrom(functionType.getOutputType())) {
logger.debug("Transforming Kotlin lambda " + beanName
+ " to java Consumer");
@SuppressWarnings({ "rawtypes", "unchecked" })
KotlinConsumer consumer = new KotlinConsumer((Function1) bean);
bean = consumer;
}
else {
logger.debug("Transforming Kotlin lambda " + beanName
+ " to java Function");
@SuppressWarnings({ "rawtypes", "unchecked" })
KotlinFunction function = new KotlinFunction((Function1) bean);
bean = function;
}
}
else if (bean instanceof Function0) {
logger.debug("Transforming Kotlin lambda " + beanName
+ " to java Supplier");
@SuppressWarnings({ "rawtypes", "unchecked" })
KotlinSupplier supplier = new KotlinSupplier((Function0) bean);
bean = supplier;
}
return bean;
}
};
}
/**
* Wrapper for Kotlin lambda to be represented as both Java Function<I,O> as well as
* Kotlin's Function1<I,O>
*/
private static class KotlinFunction<I, O> implements Function<I, O>, Function1<I, O> {
/**
* Wrapper for Kotlin lambda to be represented as both Java Function<I,O> as well as Kotlin's Function1<I,O>
*/
private static class KotlinFunction<I,O> implements Function<I,O>, Function1<I,O> {
private final Function1<I, O> kotlinLambda;
private final Function1<I,O> kotlinLambda;
KotlinFunction(Function1<I, O> kotlinLambda) {
this.kotlinLambda = kotlinLambda;
}
KotlinFunction(Function1<I,O> kotlinLambda) {
this.kotlinLambda = kotlinLambda;
}
@Override
public O apply(I i) {
return this.kotlinLambda.invoke(i);
}
@Override
public O apply(I i) {
return this.kotlinLambda.invoke(i);
}
@Override
public O invoke(I i) {
return this.apply(i);
}
}
@Override
public O invoke(I i) {
return this.apply(i);
}
}
/**
* Wrapper for Kotlin lambda to be represented as both Java Consumer<I> as well as
* Kotlin's Function1<I,Unit>
*/
private static class KotlinConsumer<I, U> implements Consumer<I>, Function1<I, U> {
/**
* Wrapper for Kotlin lambda to be represented as both Java Consumer<I> as well as Kotlin's Function1<I,Unit>
*/
private static class KotlinConsumer<I,Unit> implements Consumer<I>, Function1<I,Unit> {
private final Function1<I, U> kotlinLambda;
private final Function1<I,Unit> kotlinLambda;
KotlinConsumer(Function1<I, U> kotlinLambda) {
this.kotlinLambda = kotlinLambda;
}
KotlinConsumer(Function1<I,Unit> kotlinLambda) {
this.kotlinLambda = kotlinLambda;
}
@Override
public U invoke(I i) {
return this.kotlinLambda.invoke(i);
}
@Override
public Unit invoke(I i) {
return this.kotlinLambda.invoke(i);
}
@Override
public void accept(I i) {
this.kotlinLambda.invoke(i);
}
}
@Override
public void accept(I i) {
this.kotlinLambda.invoke(i);
}
}
/**
* Wrapper for Kotlin lambda to be represented as both Java Supplier<O> as well as
* Kotlin's Function0<O>
*/
private static class KotlinSupplier<O> implements Supplier<O>, Function0<O> {
/**
* Wrapper for Kotlin lambda to be represented as both Java Supplier<O> as well as Kotlin's Function0<O>
*/
private static class KotlinSupplier<O> implements Supplier<O>, Function0<O> {
private final Function0<O> kotlinLambda;
private final Function0<O> kotlinLambda;
KotlinSupplier(Function0<O> kotlinLambda) {
this.kotlinLambda = kotlinLambda;
}
KotlinSupplier(Function0<O> kotlinLambda) {
this.kotlinLambda = kotlinLambda;
}
@Override
public O get() {
return this.invoke();
}
@Override
public O get() {
return this.invoke();
}
@Override
public O invoke() {
return this.kotlinLambda.invoke();
}
}
@Override
public O invoke() {
return this.kotlinLambda.invoke();
}
}
}