Resolve repository method return types against the repository interface#3512
Open
Develop-KIM wants to merge 1 commit into
Open
Resolve repository method return types against the repository interface#3512Develop-KIM wants to merge 1 commit into
Develop-KIM wants to merge 1 commit into
Conversation
Query execution resolved the return type of a repository method from the method declaration alone. A return type declared as a type variable on a base interface, such as `T findById(ID id)` on a generic `@NoRepositoryBean` base, therefore resolved to the type variable's bound rather than the concrete domain type. Result post-processing then saw a target type of `Object`, concluded that no processing was required and returned the store's `Optional` unchanged, so callers observed an `Optional` where the method declared `T`. We now register the repository interface as containing class of the return type's `MethodParameter` so that the type variable resolves against the concrete repository interface, following what `MethodLookups` already does for parameter types. The regression test added for spring-projects#3125 passed because it constructed the `MethodParameter` with the containing class itself, which the production call site never did. The test added here covers the proxy instead. Closes spring-projects#3507 Related tickets spring-projects#3125 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Develop-KIM <kimdonghwan913@gmail.com>
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.
A generic
@NoRepositoryBeanbase declaringT findById(ID id)hands back anOptional<T>at runtime instead ofT.QueryExecutorMethodInterceptor.invoke(…)builds the return type asnew MethodParameter(method, -1)with no containing class, soTresolves againstRepository<T, ID>and ends up asObject.QueryExecutionResultHandler.processingRequired(…)then asks!targetType.isInstance(source), which isfalsefor a target type ofObject, and theOptionalgoes back to the caller untouched.This registers the repository interface as containing class of that
MethodParameter, the same thingMethodLookupsalready does for parameter types.The test added for #3125 didn't catch this because it calls
.withContainingClass(…)on theMethodParameteritself, which the production call site never did, so it was green against a code path that doesn't exist. I put the new test on the proxy instead — it fails on current main withClassCastException: class java.util.Optional cannot be cast to class …sample.Userand passes with the change. Full suite green (3856 tests).Written with AI assistance (Claude Code); the commit carries the co-author trailer.