spring-projects / spring-projects/spring-data-commons
AOT accessor generation does not consider nested types more than 1 level of depth
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 838
- Forks
- 730
- PR merge metrics
- No merged PRs in 30d
Description
Currently, in AOT generation, types that are 2 or more layers of generics deep, such as
VinMap<K, Map<K, V>>
do not have accessors generated for them ahead of time.
On the other hand
VinMap<K, V>
has an accessor generated for it ahead of time,
From my testing, it seems that the output of line 127 of DefaultAotRepositoryContext is where the issues starts at - when V is nested two layers of generics deep, it isn't a part of the return value of this call; while if it's only one layer of generics deep, it is.
Due to the fact that no generator is being generated in the first case of V being two layers of generics deep, it causes the following exception to be thrown in runtime of the generated native image, when calling the repository associated to the entity class that references type V:
java.lang.IllegalStateException: org.springframework.cglib.core.CodeGenerationException:
com.oracle.svm.core.jdk.UnsupportedFeatureError
-->
Classes cannot be defined at runtime by default when using ahead-of-time Native Image compilation.
Concrete example:
@Repository
public interface EntityRepository extends MongoRepository<EntityClass, String> {
}
@Document("entities")
@Data
public class EntityClass {
@Id
private String id;
private Map<String, EntityChildOne> one;
private Map<String, Map<String, EntityChildTwo>> two;
}
EntityChildOne and EntityChildTwo are both simple POJOs with a single field.
Running the following:
mvn clean compile spring-boot:process-aot && find target/ -iname "*Entity*Accessor*"
Returns the following output, which only contains __Accessor(s) for EntityClass and EntityChildOne, regardless of the fact that EntityChildTwo is being referenced.
target/spring-aot/main/classes/com/example/spring_data_accessor_generation_issue/EntityChildOne__Accessor_1po17f.class
target/spring-aot/main/classes/com/example/spring_data_accessor_generation_issue/EntityClass__Accessor_r2t2jh.class
target/classes/com/example/spring_data_accessor_generation_issue/EntityChildOne__Accessor_1po17f.class
target/classes/com/example/spring_data_accessor_generation_issue/EntityClass__Accessor_r2t2jh.class
Considering that the runtime code tries to generate the EntityChildTwo accessor (which fails when running in a native context), is this something that could be fixed?
In case someone else has the same issue -> my current workaround is adding a final field with no getters/setters and annotating it with @Transient, which allows it to be picked up by the AOT processing but completely ignored otherwise.
Reproducing
Feel free to use this sample repository for reproducing the issue. Versions used:
- Java version: 25.0.4
spring-data-commonsversion: 4.0.7/4.1.1 (tested with both)- GraalVM version: 25.2.4
Thanks in advance.
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 at line 127 of src/main/java/org/springframework/data/repository/config/DefaultAotRepositoryContext.java and reproduce the issue with the linked sample repository using the provided Maven AOT command. Check why EntityChildTwo is absent from the generated accessor output while EntityChildOne is included. Done means nested generic types receive accessors during AOT processing and the runtime native-image failure is avoided.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, build-system
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100