Inspect bean definition more thoroughly for factory arguments

Fixes gh-153
This commit is contained in:
Dave Syer
2018-03-02 11:28:33 +00:00
parent dc008cc24d
commit 5528659b4b
4 changed files with 117 additions and 5 deletions

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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());
}
}