Skip to content

findById declared as T on a generic repository base returns Optional<T> #3507

Description

@jschmied

A @NoRepositoryBean base repository interface, parameterized as <T, ID> and extending PagingAndSortingRepository + QueryByExampleExecutor (NOT CrudRepository), declares T findById(ID) to return the unwrapped entity. When a concrete leaf
repository extends it WITHOUT redeclaring findById, the generated proxy returns Optional instead of the declared T. Redeclaring T findById(ID) concretely on the leaf is the only workaround. This is #3125 (milestone "fixed 3.2.9"), but it still reproduces on the latest 3.5.x AND the latest 4.1.x -- so it has regressed or never covered this two-parent base shape.

CLEAN EXAMPLES

Base (declares T findById, no CrudRepository):

    @NoRepositoryBean
    public interface AbstractJpaDAO<T, ID>
            extends QueryByExampleExecutor<T>, PagingAndSortingRepository<T, ID> {
        T findById(ID id);
    }

Leaf WITHOUT redeclaration -> BUG:

    public interface FooDAO extends AbstractJpaDAO<Foo, Long> { }
    // fooDAO.findById(1L)  ->  runtime type java.util.Optional  (declared: Foo)

Leaf WITH redeclaration -> WORKS:

    public interface FooWorkaroundDAO extends AbstractJpaDAO<Foo, Long> {
        @Override Foo findById(Long id);
    }
    // fooWorkaroundDAO.findById(1L)  ->  Foo

Observing it (assign to Object so no synthetic checkcast masks the real type):

    Object result = fooDAO.findById(id);
    assertThat(result).isInstanceOf(Foo.class);   // fails: actual is Optional[Foo]

Actual vs expected:

expected: instance of com.example.repro.Foo
actual  : Optional[com.example.repro.Foo@...]   (java.util.Optional)

VERSIONS

Version     spring-data-commons   Hibernate    leaf w/o redeclare   workaround
---------   -------------------   ---------    ------------------   ----------
Boot 3.5.5  3.5.3                 6.6.26       Optional[Foo]  FAIL   Foo  OK
Boot 4.1.0  4.1.0                 7.4.1        Optional[Foo]  FAIL   Foo  OK

Java 21, H2 (in-memory). Only public Maven Central artifacts required.

HOW TO RUN

unzip the archive, then:  mvn test

Related issue: #3125

sdc-3125-repro-boot4.zip
sdc-3125-repro-boot35.zip

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions