From 00ec268aca5b393c6e0c23d08c88541074f2b7eb Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Tue, 29 Oct 2019 19:49:32 +0100 Subject: [PATCH] GH-420 Fix discovery of function type from class Fix introspection over ScannedGenericBeanDefinition Resolves #420 --- .../context/catalog/FunctionTypeUtils.java | 9 ++++--- .../context/config/FunctionContextUtils.java | 11 +++++++++ .../catalog/FunctionTypeUtilsTests.java | 24 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java index 2f8699419..ee70a00ba 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java @@ -81,13 +81,16 @@ public final class FunctionTypeUtils { */ public static Method discoverFunctionalMethod(Class pojoFunctionClass) { if (Supplier.class.isAssignableFrom(pojoFunctionClass)) { - return Stream.of(ReflectionUtils.getDeclaredMethods(pojoFunctionClass)).filter(m -> m.getName().equals("get")).findFirst().get(); + return Stream.of(ReflectionUtils.getDeclaredMethods(pojoFunctionClass)).filter(m -> !m.isSynthetic() + && m.getName().equals("get")).findFirst().get(); } else if (Consumer.class.isAssignableFrom(pojoFunctionClass) || BiConsumer.class.isAssignableFrom(pojoFunctionClass)) { - return Stream.of(ReflectionUtils.getDeclaredMethods(pojoFunctionClass)).filter(m -> m.getName().equals("accept")).findFirst().get(); + return Stream.of(ReflectionUtils.getDeclaredMethods(pojoFunctionClass)).filter(m -> !m.isSynthetic() + && m.getName().equals("accept")).findFirst().get(); } else if (Function.class.isAssignableFrom(pojoFunctionClass) || BiFunction.class.isAssignableFrom(pojoFunctionClass)) { - return Stream.of(ReflectionUtils.getDeclaredMethods(pojoFunctionClass)).filter(m -> m.getName().equals("apply")).findFirst().get(); + return Stream.of(ReflectionUtils.getDeclaredMethods(pojoFunctionClass)).filter(m -> !m.isSynthetic() + && m.getName().equals("apply")).findFirst().get(); } List methods = new ArrayList<>(); diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java index fd90b6b64..1665b9d81 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java @@ -28,7 +28,9 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; import org.springframework.cloud.function.core.FunctionFactoryMetadata; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; import org.springframework.core.ResolvableType; import org.springframework.core.io.Resource; import org.springframework.core.type.MethodMetadata; @@ -58,6 +60,15 @@ public abstract class FunctionContextUtils { if (definition == null) { return null; } + else if (definition instanceof ScannedGenericBeanDefinition) { + try { + return FunctionTypeUtils.discoverFunctionTypeFromClass(definition.getBeanClass()); + } + catch (Exception e) { + // ignore since name may not be actually resolved to a class in some cases + // java.lang.IllegalStateException: Bean class name [functions.Greeter] has not been resolved into an actual Class + } + } Object source = definition.getSource(); diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java index 40460b2ea..83c0da597 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtilsTests.java @@ -17,6 +17,7 @@ package org.springframework.cloud.function.context.catalog; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.Date; import java.util.List; @@ -44,6 +45,23 @@ import static org.assertj.core.api.Assertions.assertThat; @SuppressWarnings("unused") public class FunctionTypeUtilsTests { + @Test + public void testFunctionTypeFrom() throws Exception { + Type type = FunctionTypeUtils.discoverFunctionTypeFromClass(SimpleConsumer.class); + assertThat(type).isInstanceOf(ParameterizedType.class); + Type wrapperType = ((ParameterizedType) type).getActualTypeArguments()[0]; + assertThat(wrapperType).isInstanceOf(ParameterizedType.class); + assertThat(wrapperType.getTypeName()).contains("Flux"); + + Type innerWrapperType = ((ParameterizedType) wrapperType).getActualTypeArguments()[0]; + assertThat(innerWrapperType).isInstanceOf(ParameterizedType.class); + assertThat(innerWrapperType.getTypeName()).contains("Message"); + + Type targetType = ((ParameterizedType) innerWrapperType).getActualTypeArguments()[0]; + assertThat(targetType).isEqualTo(String.class); + System.out.println(); + } + @Test public void testInputCount() throws Exception { int inputCount = FunctionTypeUtils.getInputCount(getReturnType("function")); @@ -205,4 +223,10 @@ public class FunctionTypeUtilsTests { private interface MyMessageConsumer extends MessageConsumer { } + + public static class SimpleConsumer implements Consumer>> { + @Override + public void accept(Flux> messageFlux) { + } + } }