From 1814d1af9458824a7bdf64867d81369207924448 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 29 Oct 2025 12:01:37 +0100 Subject: [PATCH 1/3] Prepare issue branch. --- pom.xml | 2 +- spring-data-envers/pom.xml | 4 ++-- spring-data-jpa-distribution/pom.xml | 2 +- spring-data-jpa/pom.xml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index d55e75008d..118544399a 100755 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-jpa-parent - 4.0.0-SNAPSHOT + 4.0.x-GH-4065-SNAPSHOT pom Spring Data JPA Parent diff --git a/spring-data-envers/pom.xml b/spring-data-envers/pom.xml index 0bdf2c8e7e..4875483c80 100755 --- a/spring-data-envers/pom.xml +++ b/spring-data-envers/pom.xml @@ -5,12 +5,12 @@ org.springframework.data spring-data-envers - 4.0.0-SNAPSHOT + 4.0.x-GH-4065-SNAPSHOT org.springframework.data spring-data-jpa-parent - 4.0.0-SNAPSHOT + 4.0.x-GH-4065-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa-distribution/pom.xml b/spring-data-jpa-distribution/pom.xml index af5244a230..3d25511a87 100644 --- a/spring-data-jpa-distribution/pom.xml +++ b/spring-data-jpa-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-jpa-parent - 4.0.0-SNAPSHOT + 4.0.x-GH-4065-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml index bb01d9f6f6..2bfc31f758 100644 --- a/spring-data-jpa/pom.xml +++ b/spring-data-jpa/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-jpa - 4.0.0-SNAPSHOT + 4.0.x-GH-4065-SNAPSHOT Spring Data JPA Spring Data module for JPA repositories. @@ -16,7 +16,7 @@ org.springframework.data spring-data-jpa-parent - 4.0.0-SNAPSHOT + 4.0.x-GH-4065-SNAPSHOT ../pom.xml From 7193e2fd0dd54eea19cf152395286b134be31e16 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 29 Oct 2025 12:03:06 +0100 Subject: [PATCH 2/3] Update security.adoc. --- SECURITY.adoc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/SECURITY.adoc b/SECURITY.adoc index de17b3ec0c..654bfbea58 100644 --- a/SECURITY.adoc +++ b/SECURITY.adoc @@ -1,9 +1,15 @@ = Security Policy -== Supported Versions +== Reporting a Vulnerability -Please see the https://spring.io/projects/spring-data-jpa[Spring Data JPA] project page for supported versions. +Please, https://github.com/spring-projects/security-advisories/security/advisories/new[open a draft security advisory] if you need to disclose and discuss a security issue in private with the Spring Data team. +Note that we only accept reports against https://spring.io/projects/spring-data#support[supported versions]. -== Reporting a Vulnerability +For more details, check out our https://spring.io/security-policy[security policy]. + +== JAR signing + +Spring Data JARs released on Maven Central are signed. +You'll find more information about the key here: https://spring.io/GPG-KEY-spring.txt -Please don't raise security vulnerabilities here. Head over to https://pivotal.io/security to learn how to disclose them responsibly. +Versions released prior to 2023 may be signed with a different key. From ed7f52d9791f974852d9f7b6fa7a68de89521aab Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 12 Nov 2025 10:51:46 +0100 Subject: [PATCH 3/3] Include AOT section from data commons. See: spring-projects/spring-data-commons#3384 --- .../antora/modules/ROOT/pages/jpa/aot.adoc | 191 +----------------- 1 file changed, 11 insertions(+), 180 deletions(-) diff --git a/src/main/antora/modules/ROOT/pages/jpa/aot.adoc b/src/main/antora/modules/ROOT/pages/jpa/aot.adoc index ec06946abd..3bf124eb12 100644 --- a/src/main/antora/modules/ROOT/pages/jpa/aot.adoc +++ b/src/main/antora/modules/ROOT/pages/jpa/aot.adoc @@ -1,73 +1,19 @@ -= Ahead of Time Optimizations +include::{commons}@data-commons::page$aot.adoc[] -This chapter covers Spring Data's Ahead of Time (AOT) optimizations that build upon {spring-framework-docs}/core/aot.html[Spring's Ahead of Time Optimizations]. +[[aot.repositories.jpa]] +== JPA Ahead of Time Repositories -[[aot.bestpractices]] -== Best Practices - -=== Annotate your Domain Types - -During application startup, Spring scans the classpath for domain classes for early processing of entities. -By annotating your domain types with Spring Data-specific `@Table`, `@Document` or `@Entity` annotations you can aid initial entity scanning and ensure that those types are registered with `ManagedTypes` for Runtime Hints. -Classpath scanning is not possible in native image arrangements and so Spring has to use `ManagedTypes` for the initial entity set. - -[[aot.hints]] -== Runtime Hints - -Running an application as a native image requires additional information compared to a regular JVM runtime. -Spring Data contributes {spring-framework-docs}/core/aot.html#aot.hints[Runtime Hints] during AOT processing for native image usage. -These are in particular hints for: - -* Auditing -* `ManagedTypes` to capture the outcome of class-path scans -* Repositories -** Reflection hints for entities, return types, and Spring Data annotations -** Repository fragments -** Querydsl `Q` classes -** Kotlin Coroutine support -* Web support (Jackson Hints for `PagedModel`) - -[[aot.repositories]] -== Ahead of Time Repositories - -AOT Repositories are an extension to AOT processing by pre-generating eligible query method implementations. -Query methods are opaque to developers regarding their underlying queries being executed in a query method call. -AOT repositories contribute query method implementations based on derived, annotated, and named queries that are known at build-time. -This optimization moves query method processing from runtime to build-time, which can lead to a significant performance improvement as query methods do not need to be analyzed reflectively upon each application start. - -The resulting AOT repository fragment follows the naming scheme of `Impl__Aot` and is placed in the same package as the repository interface. -You can find all queries in their String form for generated repository query methods. - -NOTE: Consider AOT repository classes an internal optimization. -Do not use them directly in your code as generation and implementation details may change in future releases. - -=== Running with AOT Repositories - -AOT is a mandatory step to transform a Spring application to a native executable, so it is automatically enabled when running in this mode. -When AOT is enabled (either for native compilation or by setting `spring.aot.enabled=true`), AOT repositories are automatically enabled by default. - -You can disable AOT repository generation entirely or only disable JPA AOT repositories: - -* Set the `spring.aot.repositories.enabled=false` property to disable generated repositories for all Spring Data modules. -* Set the `spring.aot.jpa.repositories.enabled=false` property to disable only JPA AOT repositories. - -AOT repositories contribute configuration changes to the actual repository bean registration to register the generated repository fragment. - -NOTE: When AOT optimizations are included, some decisions that have been taken at build-time are hard-coded in the application setup. -For instance, profiles that have been enabled at build-time are automatically enabled at runtime as well. -Also, the Spring Data module implementing a repository is fixed. -Changing the implementation requires AOT re-processing. +AOT repositories filter methods that are eligible for AOT processing. +These are typically all query methods that are not backed by an xref:repositories/custom-implementations.adoc[implementation fragment]. -NOTE: AOT processing avoids database access. +[NOTE] +==== +AOT processing avoids database access. Therefore, it initializes an in-memory Hibernate instance for metadata collection. Types for the Hibernate configuration are determined by our AOT metadata collector. We prefer using a `PersistentEntityTypes` bean if available and fall back to `PersistenceUnitInfo` or our own discovered types. If our type scanning is not sufficient for your arrangement, you can enable direct `EntityManagerFactory` usage by configuring the `spring.aot.jpa.repositories.use-entitymanager=true` property. - -=== Eligible Methods - -AOT repositories filter methods that are eligible for AOT processing. -These are typically all query methods that are not backed by an xref:repositories/custom-implementations.adoc[implementation fragment]. +==== **Supported Features** @@ -85,7 +31,8 @@ Mind that using Value Expressions requires expression parsing and contextual inf * Requires Hibernate for AOT processing. * `QueryRewriter` must be a no-args class. `QueryRewriter` beans are not yet supported. -* Methods accepting `ScrollPosition` (e.g. `Keyset` pagination) are not yet supported +* Methods accepting `ScrollPosition` (e.g. `Keyset` pagination) are not yet supported. +* Custom Collection return types (e.g. `io.vavr.collection`, `"org.eclipse.collections`) are not yet supported. **Excluded methods** @@ -93,119 +40,3 @@ Mind that using Value Expressions requires expression parsing and contextual inf * Methods whose implementation would be overly complex ** Methods accepting `ScrollPosition` (e.g. `Keyset` pagination) ** Dynamic projections - -[[aot.repositories.json]] -== Repository Metadata - -AOT processing introspects query methods and collects metadata about repository queries. -Spring Data JPA stores this metadata in JSON files that are named like the repository interface and stored next to it (i.e. within the same package). -Repository JSON Metadata contains details about queries and fragments. -An example for the following repository is shown below: - -==== -[source,java] ----- -interface UserRepository extends CrudRepository { - - List findUserNoArgumentsBy(); <1> - - Page findPageOfUsersByLastnameStartingWith(String lastname, Pageable page); <2> - - @Query("select u from User u where u.emailAddress = ?1") - User findAnnotatedQueryByEmailAddress(String emailAddress); <3> - - User findByEmailAddress(String emailAddress); <4> - - @Procedure(value = "sp_add") - Integer providedProcedure(@Param("arg") Integer arg); <5> -} ----- - -<1> Derived query without arguments. -<2> Derived query using pagination. -<3> Annotated query. -<4> Named query. -<5> Stored procedure with a provided procedure name. -While stored procedure methods are included in JSON metadata, their method code blocks are not generated in AOT repositories. -==== - -[source,json] ----- -{ - "name": "com.acme.UserRepository", - "module": "JPA", - "type": "IMPERATIVE", - "methods": [ - { - "name": "findUserNoArgumentsBy", - "signature": "public abstract java.util.List com.acme.UserRepository.findUserNoArgumentsBy()", - "query": { - "query": "SELECT u FROM com.acme.User u" - } - }, - { - "name": "findPageOfUsersByLastnameStartingWith", - "signature": "public abstract org.springframework.data.domain.Page com.acme.UserRepository.findPageOfUsersByLastnameStartingWith(java.lang.String,org.springframework.data.domain.Pageable)", - "query": { - "query": "SELECT u FROM com.acme.User u WHERE u.lastname LIKE ?1 ESCAPE '\\'", - "count-query": "SELECT COUNT(u) FROM com.acme.User u WHERE u.lastname LIKE ?1 ESCAPE '\\'" - } - }, - { - "name": "findAnnotatedQueryByEmailAddress", - "signature": "public abstract com.acme.User com.acme.UserRepository.findAnnotatedQueryByEmailAddress(java.lang.String)", - "query": { - "query": "select u from User u where u.emailAddress = ?1" - } - }, - { - "name": "findByEmailAddress", - "signature": "public abstract com.acme.User com.acme.UserRepository.findByEmailAddress(java.lang.String)", - "query": { - "name": "User.findByEmailAddress", - "query": "SELECT u FROM User u WHERE u.emailAddress = ?1" - } - }, - { - "name": "providedProcedure", - "signature": "public abstract java.lang.Integer com.acme.UserRepository.providedProcedure(java.lang.Integer)", - "query": { - "procedure": "sp_add" - } - }, - { - "name": "count", - "signature": "public abstract long org.springframework.data.repository.CrudRepository.count()", - "fragment": { - "fragment": "org.springframework.data.jpa.repository.support.SimpleJpaRepository" - } - } - ] -} ----- - -Queries may contain the following fields: - -* `query`: Query descriptor if the method is a query method. -** `name`: Name of the named query if the query is a named one. -** `query` the query used to obtain the query method result from `EntityManager` -** `count-name`: Name of the named count query if the count query is a named one. -** `count-query`: The count query used to obtain the count for query methods using pagination. -** `procedure-name`: Name of the named stored procedure if the stored procedure is a named one. -** `procedure`: Stored procedure name if the query method uses stored procedures. -* `fragment`: Target fragment if the method call is delegated to a store (repository base class, functional fragment such as Querydsl) or user fragment. -Fragments are either described with just `fragment` if there is no further interface or as `interface` and `fragment` tuple in case there is an interface (such as Querydsl or user-declared fragment interface). - -[NOTE] -.Normalized Query Form -==== -Static analysis of queries allows only a limited representation of runtime query behavior. -Queries are represented in their normalized (pre-parsed and rewritten) form: - -* Value Expressions are replaced with bind markers. -* Queries follow the specified query language (JPQL or native) and do not represent the final SQL query. -Spring Data cannot derive the final SQL queries as this is database-specific and depends on the actual runtime environment and parameters (e.g. Entity Graphs, Lazy Loading). -* Query Metadata does not reflect bind-value processing. -`StartingWith`/`EndingWith` queries prepend/append the wildcard character `%` to the actual bind value. -* Runtime Sort information cannot be incorporated in the query string itself as that detail is not known at build-time. -====