Has anyone tried playing with Loom in Kotlin and S...
# spring
a
Has anyone tried playing with Loom in Kotlin and Spring Boot? I’m following this blog post by Spring. But when I print the threads to the console, they aren’t virtual threads!
Copy code
Is Virtual Thread: false | Thread[#38,http-nio-8080-exec-3,5,main]
Is Virtual Thread: false | Thread[#37,http-nio-8080-exec-2,5,main]
Is Virtual Thread: false | Thread[#41,http-nio-8080-exec-6,5,main]
Is Virtual Thread: false | Thread[#36,http-nio-8080-exec-1,5,main]
Is Virtual Thread: false | Thread[#39,http-nio-8080-exec-4,5,main]
The full code is here: https://github.com/aseemsavio/loomgraphql Here’s the code:
Copy code
package com.asavio.loomgraphql

import org.apache.coyote.ProtocolHandler
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
import org.springframework.boot.runApplication
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.core.task.AsyncTaskExecutor
import org.springframework.core.task.support.TaskExecutorAdapter
import org.springframework.graphql.data.method.annotation.QueryMapping
import org.springframework.stereotype.Controller
import java.util.concurrent.Executors


@SpringBootApplication
class LoomgraphqlApplication

fun main(args: Array<String>) {
    runApplication<LoomgraphqlApplication>(*args)
}

@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
fun asyncTaskExecutor(): AsyncTaskExecutor? {
    return TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor())
}

@Bean
fun protocolHandlerVirtualThreadExecutorCustomizer(): TomcatProtocolHandlerCustomizer<*>? {
    return TomcatProtocolHandlerCustomizer { protocolHandler: ProtocolHandler ->
        protocolHandler.executor = Executors.newVirtualThreadPerTaskExecutor()
    }
}

@Controller
class PeopleController {

    @QueryMapping
    fun people(): List<Person> {
        println("Is Virtual Thread: ${Thread.currentThread().isVirtual} | ${Thread.currentThread()}")
        return listOf(
            Person("jdgahjdagdahjdg", "Jon", 25),
            Person("ddgahjdagdahjdg", "Snow", 26),
            Person("gdgahjdagdahjdg", "Arya", 23),
            Person("qdgahjdagdahjdg", "Stark", 21),
        )
    }

}

data class Person(val id: String, val name: String, val age: Int)
This is my build.gradle.kts file.
Copy code
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.0.1"
    id("io.spring.dependency-management") version "1.1.0"
    id("org.graalvm.buildtools.native") version "0.9.18"
    kotlin("jvm") version "1.8.0"
    kotlin("plugin.spring") version "1.8.0"
}

group = "com.asavio"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_19

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-graphql")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework:spring-webflux")
    testImplementation("org.springframework.graphql:spring-graphql-test")
}

val preview = "--enable-preview"

tasks.withType<org.springframework.boot.gradle.tasks.run.BootRun> {
    jvmArgs = mutableListOf(preview)
}

tasks.withType<JavaExec> {
    jvmArgs = mutableListOf(preview)
}

tasks.withType<JavaCompile> {
    options.encoding = "UTF-8"
    options.compilerArgs.add(preview)
    options.compilerArgs.add("-Xlint:preview")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "19"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}
r
I suspect that you should put the functions annotated with
@Bean
(so
asyncTaskExecutor()
and
protocolHandlerVirtualThreadExecutorCustomizer()
in a class annotated with
@Configuration
, probably these beans are not being created now
a
I wonder why you need this? 🙂
a
Adding the bean functions to a class did it. Thanks 🙂
Copy code
Is Virtual Thread: true | VirtualThread[#40]/runnable@ForkJoinPool-1-worker-1
Is Virtual Thread: true | VirtualThread[#50]/runnable@ForkJoinPool-1-worker-1
Is Virtual Thread: true | VirtualThread[#52]/runnable@ForkJoinPool-1-worker-1
Is Virtual Thread: true | VirtualThread[#54]/runnable@ForkJoinPool-1-worker-1
In case you’re wondering, why virtual threads instead of Kotlin, I thought virtual threads are better for support with legacy Java libraries (provided they don’t pin the VTs too much) 🙂
168 Views