Skip to content

Avoid Kotlin reflection in KotlinReflectionUtils.isSuspend for methods without a Continuation parameter #3544

Description

@gregjotau

KotlinReflectionUtils.isSuspend(Method) resolves the KFunction for every Kotlin method it is asked about via ReflectJvmMapping.getKotlinFunction(method). That lookup materializes all members of the declaring KClass through Kotlin reflection (metadata deserialization plus a linear scan comparing javaMethod for each member), only to read KFunction.isSuspend().

AbstractRepositoryMetadata.getReturnType(Method) calls isSuspend for every query method during repository initialization, and RepositoryMethodInvoker calls it again when the invoker is created. For Kotlin repositories that do not use coroutines at all, this is pure overhead: a suspend function always compiles to a JVM method whose last parameter is kotlin.coroutines.Continuation, so a method without such a parameter can never be suspending. Spring Framework's KotlinDetector.isSuspendingFunction(Method) performs exactly that check without loading Kotlin reflection, and QueryExecutionResultHandler in this module already relies on it.

In a Spring Boot 4.2.0-SNAPSHOT / Spring Data 2026.1.0-SNAPSHOT Kotlin application with 243 JPA repositories and 1,418 non-synthetic repository interface methods, a wall-clock startup profile (async-profiler, 2 ms sampling, extracted Boot layout) attributed 241 of 8,694 main-thread samples (2.8 % of startup, about 0.5 s) to KotlinReflectionUtils.isSuspend, all of it below ReflectJvmMapping.getKotlinFunction. A cold-JVM micro-benchmark that calls isSuspend for those 1,418 methods takes 1,146–1,341 ms on current main and 3–4 ms when the Continuation parameter check runs first (5 runs each, JDK 27, Apple M5 Max).

Proposal: short-circuit isSuspend with KotlinDetector.isSuspendingFunction(method) before touching Kotlin reflection, keeping the KFunction.isSuspend() verification for methods that do declare a trailing Continuation parameter so the result stays identical for non-suspending functions that take a Continuation argument explicitly.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions