Inspect bean definition more thoroughly for factory arguments
Fixes gh-153
This commit is contained in:
@@ -16,7 +16,7 @@ The sample app creates the shaded jar file, with an `azure` classifier for deplo
|
||||
|
||||
=== JSON Configuration
|
||||
|
||||
The Azure tooling needs to find some JSON configuration files to tell it how to deploy and intergrate the function (e.g. which Java class to use as the entry point, and which triggers to use). Those files can be created with the Maven plugin for a non-Spring function, but the tooling doesn't work yet with the adapter in its current form. There is an example `function.json` in the sample which hooks the function up as an HTTP endpoint:
|
||||
The Azure tooling needs to find some JSON configuration files to tell it how to deploy and integrate the function (e.g. which Java class to use as the entry point, and which triggers to use). Those files can be created with the Maven plugin for a non-Spring function, but the tooling doesn't work yet with the adapter in its current form. There is an example `function.json` in the sample which hooks the function up as an HTTP endpoint:
|
||||
|
||||
```
|
||||
{
|
||||
|
||||
@@ -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