spring-cloud-function icon indicating copy to clipboard operation
spring-cloud-function copied to clipboard

Kotlin: FunctionTypeUtils do not support Kotlin functions following functional bean definition approach

Open ArnauAregall opened this issue 1 year ago • 5 comments

Describe the bug

I am trying to follow the reference documentation section about registering functions with the Functional Bean definition approach, but using Kotlin.

Probably I am doing something wrong, but I could not find a way to define the FunctionRegistration#type either than using org.springframework.cloud.function.context.catalog.FunctionTypeUtils#functionType(), but seems it does not support Kotlin functions.

java.lang.IllegalArgumentException: Must be one of Supplier, Function, Consumer or FunctionRegistration. Was interface kotlin.jvm.functions.Function1
	at org.springframework.util.Assert.isTrue(Assert.java:122) ~[spring-core-6.0.9.jar:6.0.9]
	at org.springframework.cloud.function.context.catalog.FunctionTypeUtils.assertSupportedTypes(FunctionTypeUtils.java:536) ~[spring-cloud-function-context-4.0.3.jar:4.0.3]
	at org.springframework.cloud.function.context.catalog.FunctionTypeUtils.getInputType(FunctionTypeUtils.java:327) ~[spring-cloud-function-context-4.0.3.jar:4.0.3]
	at org.springframework.cloud.function.context.FunctionRegistration.type(FunctionRegistration.java:129) ~[spring-cloud-function-context-4.0.3.jar:4.0.3]
	at tech.aaregall.lab.AppFunctional.initialize(AppFunctional.kt:22) ~[main/:na]

Versions:

  • Spring Boot 3.1.0
  • Kotlin 1.8.21
  • JDK 17
  • Spring Cloud 2002.0.3 (spring-cloud-function-kotlin:4.0.3)

Sample

package tech.aaregall.lab

import org.springframework.boot.SpringBootConfiguration
import org.springframework.cloud.function.context.FunctionRegistration
import org.springframework.cloud.function.context.FunctionalSpringApplication
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils
import org.springframework.context.ApplicationContextInitializer
import org.springframework.context.support.GenericApplicationContext

@SpringBootConfiguration
class AppFunctional : ApplicationContextInitializer<GenericApplicationContext> {

    fun uppercase(): (String) -> String {
        return { it.uppercase() }
    }

    override fun initialize(context: GenericApplicationContext) {
        context.registerBean("demo", FunctionRegistration::class.java,
            FunctionRegistration(uppercase())
                .type(FunctionTypeUtils.functionType(String::class.java, String::class.java))
        )
    }
}

fun main(args: Array<String>) {
    FunctionalSpringApplication.run(AppFunctional::class.java, *args)
}
plugins {
	id("org.springframework.boot")
	id("io.spring.dependency-management")
	kotlin("jvm")
	kotlin("plugin.spring")
}

repositories {
	mavenCentral()
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-webflux")
	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
	implementation("io.projectreactor.kotlin:reactor-kotlin-extensions")
	implementation("org.springframework.cloud:spring-cloud-function-web")
	implementation("org.springframework.cloud:spring-cloud-function-kotlin")
	testImplementation("org.springframework.boot:spring-boot-starter-test")
	testImplementation("io.projectreactor:reactor-test")
}

dependencyManagement {
	imports {
		mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
	}
}

The Java version works perfectly in the same project with the same approach + same dependencies.

package tech.aaregall.lab;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.FunctionalSpringApplication;
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.support.GenericApplicationContext;

import java.util.function.Function;

@SpringBootConfiguration
public class AppFunctionalJavaVersion implements ApplicationContextInitializer<GenericApplicationContext> {

    public static void main(String[] args) {
        FunctionalSpringApplication.run(AppFunctionalJavaVersion.class, args);
    }

    public Function<String, String> uppercase() {
        return String::toUpperCase;
    }

    @Override
    public void initialize(GenericApplicationContext context) {
        context.registerBean("demo", FunctionRegistration.class,
                () -> new FunctionRegistration<>(uppercase())
                        .type(FunctionTypeUtils.functionType(String.class, String.class)));

    }
}

ArnauAregall avatar Jun 04 '23 07:06 ArnauAregall