Repository navigation
Conversation
…s without a Continuation parameter. A Kotlin suspend function always compiles to a JVM method whose last parameter is kotlin.coroutines.Continuation. Check for that parameter with KotlinDetector.isSuspendingFunction(…) before resolving the KFunction, so that regular Kotlin methods no longer materialize all members of their declaring class through Kotlin reflection. Methods that declare a trailing Continuation parameter are still verified via KFunction.isSuspend(). Also let RepositoryMethodInvoker.CoroutineAdapterInformation use isSuspend(…) instead of resolving both KFunctions itself only to read isSuspend(). Closes spring-projects#3544 Signed-off-by: Greg Taube <gregjotau@gmail.com>
Continuation parameter
mp911de
pushed a commit
that referenced
this pull request
Oct 6, 2026
…tinuation` parameter. A Kotlin suspend function always compiles to a JVM method whose last parameter is kotlin.coroutines.Continuation. Check for that parameter with KotlinDetector.isSuspendingFunction(…) before resolving the KFunction, so that regular Kotlin methods no longer materialize all members of their declaring class through Kotlin reflection. Methods that declare a trailing Continuation parameter are still verified via KFunction.isSuspend(). Also let RepositoryMethodInvoker.CoroutineAdapterInformation use isSuspend(…) instead of resolving both KFunctions itself only to read isSuspend(). Closes #3544 Original pull request: #3556 Signed-off-by: Greg Taube <gregjotau@gmail.com>
mp911de
pushed a commit
that referenced
this pull request
Oct 6, 2026
…tinuation` parameter. A Kotlin suspend function always compiles to a JVM method whose last parameter is kotlin.coroutines.Continuation. Check for that parameter with KotlinDetector.isSuspendingFunction(…) before resolving the KFunction, so that regular Kotlin methods no longer materialize all members of their declaring class through Kotlin reflection. Methods that declare a trailing Continuation parameter are still verified via KFunction.isSuspend(). Also let RepositoryMethodInvoker.CoroutineAdapterInformation use isSuspend(…) instead of resolving both KFunctions itself only to read isSuspend(). Closes #3544 Original pull request: #3556 Signed-off-by: Greg Taube <gregjotau@gmail.com>
Member
|
Thank you for your contribution. That's merged, polished, and backported now. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Recreates #3545 as requested after its source fork was deleted. This applies the original signed-off change unchanged to current
main. I consent to this change being merged.KotlinReflectionUtils.isSuspend(Method)resolves theKFunctionfor every Kotlin method throughReflectJvmMapping.getKotlinFunction(method), which materializes all members of the declaringKClassvia Kotlin reflection, only to readKFunction.isSuspend().AbstractRepositoryMetadata.getReturnType(Method)calls it for every query method during repository initialization, andRepositoryMethodInvokercalls it again per method.A
suspendfunction always compiles to a JVM method whose last parameter iskotlin.coroutines.Continuation, soKotlinDetector.isSuspendingFunction(method)(already used byQueryExecutionResultHandlerin this module) can rule out regular methods without loading Kotlin reflection. Methods that do declare a trailingContinuationparameter are still verified throughKFunction.isSuspend(), so a non-suspending function that takes aContinuationargument explicitly keeps returningfalse.RepositoryMethodInvoker.CoroutineAdapterInformation.create(...)had the same pattern (twofindKotlinFunctionlookups used only forisSuspend()); it now delegates toKotlinReflectionUtils.isSuspend(...).Measurements from the original submission
Cold-JVM micro-benchmark calling
isSuspendfor the 1,418 non-synthetic methods of the 337 Kotlin repository interfaces of a Spring Boot 4.2.0-SNAPSHOT application (JDK 27, Apple M5 Max, 5 runs each):mainisSuspendover 1,418 methodsIn a wall-clock startup profile of the same application (async-profiler, 2 ms sampling, extracted Boot layout, 243 JPA repositories),
KotlinReflectionUtils.isSuspendaccounted for 241 of 8,694 main-thread samples (2.8 % of startup), all belowReflectJvmMapping.getKotlinFunction; with this change the frame no longer appears. Part of theKClassmember computation is shared with other Kotlin reflection users during startup, so the end-to-end saving depends on what else touches those classes.Verification from the original submission
KotlinReflectionUtilsSuspendUnitTests,KotlinReflectionUtilsUnitTests,RepositoryMethodInvokerUnitTestsand bothCoroutineRepositoryMetadataUnitTestspass locally. I also verified the fragment path with a throwaway MockK-free variant ofCoroutineCrudRepositoryCustomImplementationUnitTests(suspend fragment method, regular fragment method, and suspend base methods bridging to a reactive backing repository includingFlowandUnitresults).CoroutineCrudRepositoryUnitTestsandCoroutineCrudRepositoryCustomImplementationUnitTestscould not run on my machine on eithermainor this branch because the MockK agent fails to self-attach there, so CI will have to cover those.Closes #3544
Verification on current
mainThe restored patch has the same stable Git patch ID as the original commit.
./mvnw -Dtest=KotlinReflectionUtilsSuspendUnitTests,KotlinReflectionUtilsUnitTests,RepositoryMethodInvokerUnitTests,CoroutineRepositoryMetadataUnitTests testcompleted successfully on JDK 27: 29 tests, 0 failures, 0 errors, 4 skipped (all inKotlinReflectionUtilsUnitTests). The other 25 tests passed, including both coroutine metadata test classes.