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 b4ca09b95..5c672c159 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 @@ -1,5 +1,5 @@ /* - * Copyright 2019-2022 the original author or authors. + * Copyright 2019-2025 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. @@ -63,6 +63,7 @@ import org.springframework.util.StringUtils; * * @author Oleg Zhurakousky * @author Andrey Shlykov + * @author Artem Bilan * * @since 3.0 */ @@ -382,6 +383,12 @@ public final class FunctionTypeUtils { type = FunctionContextUtils.findType(applicationContext.getBeanFactory(), beanDefinitionName); } } + else if (type instanceof ParameterizedType) { + ResolvableType resolvableType = ResolvableType.forType(type); + if (FactoryBean.class.isAssignableFrom(resolvableType.toClass())) { + return resolvableType.getGeneric(0).getType(); + } + } return type; } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java index 326a5c5ef..7c517a476 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2021 the original author or authors. + * Copyright 2019-2025 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. @@ -54,6 +54,7 @@ import reactor.util.function.Tuple2; import reactor.util.function.Tuple3; import reactor.util.function.Tuples; +import org.springframework.beans.factory.FactoryBean; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -85,6 +86,7 @@ import static org.junit.jupiter.api.Assertions.fail; /** * * @author Oleg Zhurakousky + * @author Artem Bilan * */ public class BeanFactoryAwareFunctionRegistryTests { @@ -891,6 +893,14 @@ public class BeanFactoryAwareFunctionRegistryTests { assertThat(result.size()).isEqualTo(3); } + @Test + void functionFromFactoryBeanIsProperlyResolved() { + FunctionCatalog catalog = configureCatalog(); + Function numberToStringFactoryBean = catalog.lookup("numberToStringFactoryBean"); + assertThat(numberToStringFactoryBean).isNotNull(); + assertThat(numberToStringFactoryBean.apply(1)).isEqualTo("1"); + } + @Test // see GH-707 public void testConcurrencyOnLookup() throws Exception { @@ -1342,6 +1352,23 @@ public class BeanFactoryAwareFunctionRegistryTests { public Consumer> reactivePojoConsumer() { return flux -> flux.subscribe(v -> consumerInputRef.set(v)); } + + @Bean + FactoryBean> numberToStringFactoryBean() { + return new FactoryBean<>() { + + @Override + public Function getObject() { + return Number::toString; + } + + @Override + public Class getObjectType() { + return Function.class; + } + + }; + } } @EnableAutoConfiguration