Inspect bean definition more thoroughly for factory arguments
Fixes gh-153
This commit is contained in:
@@ -20,6 +20,8 @@ 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;
|
||||
@@ -42,6 +44,7 @@ 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.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
@@ -553,15 +556,48 @@ public class ContextFunctionCatalogAutoConfiguration {
|
||||
MethodMetadataReadingVisitor visitor) {
|
||||
Class<?> factory = ClassUtils
|
||||
.resolveClassName(visitor.getDeclaringClassName(), null);
|
||||
Class<?>[] params = getParamTypes(factory, definition);
|
||||
Method method = ReflectionUtils.findMethod(factory, visitor.getMethodName(),
|
||||
params);
|
||||
Type type = method.getGenericReturnType();
|
||||
return type;
|
||||
}
|
||||
|
||||
private Method[] getCandidateMethods(final Class<?> factoryClass,
|
||||
final RootBeanDefinition mbd) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||
@Override
|
||||
public Method[] run() {
|
||||
return (mbd.isNonPublicAccessAllowed()
|
||||
? ReflectionUtils.getAllDeclaredMethods(factoryClass)
|
||||
: factoryClass.getMethods());
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
return (mbd.isNonPublicAccessAllowed()
|
||||
? ReflectionUtils.getAllDeclaredMethods(factoryClass)
|
||||
: factoryClass.getMethods());
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?>[] getParamTypes(Class<?> factory,
|
||||
AbstractBeanDefinition definition) {
|
||||
if (definition instanceof RootBeanDefinition) {
|
||||
RootBeanDefinition root = (RootBeanDefinition) definition;
|
||||
for (Method method : getCandidateMethods(factory, root)) {
|
||||
if (root.isFactoryMethod(method)) {
|
||||
return method.getParameterTypes();
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Class<?>> params = new ArrayList<>();
|
||||
for (ValueHolder holder : definition.getConstructorArgumentValues()
|
||||
.getIndexedArgumentValues().values()) {
|
||||
params.add(ClassUtils.resolveClassName(holder.getType(), null));
|
||||
}
|
||||
Method method = ReflectionUtils.findMethod(factory, visitor.getMethodName(),
|
||||
params.toArray(new Class<?>[0]));
|
||||
Type type = method.getGenericReturnType();
|
||||
return type;
|
||||
return params.toArray(new Class<?>[0]);
|
||||
}
|
||||
|
||||
private Object getField(Object target, String name) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionScan;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.cloud.function.inject.FooConfiguration;
|
||||
import org.springframework.cloud.function.scan.ScannedFunction;
|
||||
import org.springframework.cloud.function.test.GenericFunction;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
@@ -120,7 +121,26 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
.isEqualTo(String.class);
|
||||
assertThat(inspector.getInputType(catalog.lookup(Consumer.class, "foos")))
|
||||
.isEqualTo(Foo.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dependencyInjection() {
|
||||
create(DependencyInjectionConfiguration.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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalDependencyInjection() {
|
||||
create(ExternalDependencyConfiguration.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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -523,6 +543,32 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
protected static class DependencyInjectionConfiguration {
|
||||
|
||||
@Bean
|
||||
public Function<String, Foo> foos(String foo) {
|
||||
return value -> new Foo(foo + ": " + value.toUpperCase());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public String value() {
|
||||
return "Hello";
|
||||
}
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = FooConfiguration.class)
|
||||
protected static class ExternalDependencyConfiguration {
|
||||
|
||||
@Bean
|
||||
public String value() {
|
||||
return "Hello";
|
||||
}
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
protected static class AmbiguousConfiguration {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2016-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.inject;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfigurationTests.Foo;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class FooConfiguration {
|
||||
@Bean
|
||||
public Function<String, Foo> foos(String foo) {
|
||||
return value -> new Foo(foo + ": " + value.toUpperCase());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user