spring-projects / spring-projects/spring-data-relational
AOT-generated JDBC repository throws ClassCastException for query methods returning Set
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 827
- Forks
- 394
- PR merge metrics
- No merged PRs in 30d
Description
When Ahead-of-Time (AOT) repository generation is enabled, a derived (or possibly annotated) query method that declares Set<T> as its return type compiles successfully, but the generated *Impl__AotRepository class throws a ClassCastException at runtime, because the generated code builds a java.util.ArrayList internally and attempts to return/cast it as a Set.
This appears to be the JDBC-module equivalent of two already-confirmed issues in sibling Spring Data modules:
-
Spring Data JPA:
ClassCastException: ArrayList cannot be cast to Setunder native-image; -
Spring Data MongoDB: AOT-generated repository fails to compile for query methods returning Set.
Steps to reproduce
- Define a repository with a derived query method returning
Set<T>:
public interface EntityRepository extends CrudRepository<Entity, Long> {
Set<Entity> findAllBy(...);
}
-
Enable AOT repository generation (
spring.aot.enabled=true, or run thecompileAotJava/ Spring Boot AOT build task); -
Invoke the query method at runtime.
Generated Code
/**
* AOT generated implementation of {@link EntityRepository#findAllBy(...)}.
*/
public Set<Entity> findAllBy(...) {
...
...
RowMapper rowMapper = getRowMapperFactory().create(Entity.class);
List result = (List) getJdbcOperations().query(query, parameterSource, new RowMapperResultSetExtractor<>(rowMapper));
return (Set<Entity>) convertMany(result, Entity.class);
}
Expected behavior
The method should return a Set<T> (e.g. wrapping the raw query results in a LinkedHashSet or similar), matching the behavior of the reflective/non-AOT execution path, which handles the Set return type correctly.
Actual behavior
ClassCastException is thrown at runtime:
Caused by: java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.util.Set (java.util.ArrayList and java.util.Set are in module java.base of loader 'bootstrap') at com.example.aot.repository.EntityRepositoryImpl__AotRepository.findAllBy(EntityRepositoryImpl__AotRepository.java:56)
Environment
- Spring Data Relational / JDBC version:
4.x.x.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the failure with a JDBC repository method returning Set and the compileAotJava or Spring Boot AOT build task. Inspect the generated *Impl__AotRepository method and compare it with the reflective execution path. Done means the AOT-generated method returns a Set without ClassCastException and a regression test covers the behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100