diff --git a/pom.xml b/pom.xml index b82816e812..6207852557 100755 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@

2.3.232

3.2.0 5.2 + 2.3.0 9.2.0 42.7.5 23.8.0.25.04 @@ -183,6 +184,12 @@ pom import + + org.junit-pioneer + junit-pioneer + ${junit-pioneer} + test + diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml index cdb738558f..c53600dde8 100644 --- a/spring-data-jpa/pom.xml +++ b/spring-data-jpa/pom.xml @@ -100,6 +100,12 @@ test + + org.junit-pioneer + junit-pioneer + test + + org.springframework spring-core-test diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java index 95495accb4..5e971e370d 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtension.java @@ -39,6 +39,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.aot.AotDetector; import org.springframework.aot.generate.GenerationContext; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; @@ -87,6 +88,7 @@ * @author Thomas Darimont * @author Christoph Strobl * @author Mark Paluch + * @author Hyunsang Han */ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport { @@ -338,8 +340,10 @@ public static class JpaRepositoryRegistrationAotProcessor extends RepositoryRegi Environment environment = repositoryContext.getEnvironment(); + String enabledByDefault = AotDetector.useGeneratedArtifacts() ? "true" : "false"; + boolean enabled = Boolean - .parseBoolean(environment.getProperty(AotContext.GENERATED_REPOSITORIES_ENABLED, "false")); + .parseBoolean(environment.getProperty(AotContext.GENERATED_REPOSITORIES_ENABLED, enabledByDefault)); if (!enabled) { return null; } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java index 82c06f9687..e3825d671e 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java @@ -30,6 +30,9 @@ import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ClearSystemProperty; +import org.junitpioneer.jupiter.SetSystemProperty; +import org.springframework.aot.AotDetector; import org.springframework.aot.generate.ClassNameGenerator; import org.springframework.aot.generate.DefaultGenerationContext; import org.springframework.aot.generate.GenerationContext; @@ -56,14 +59,14 @@ /** * @author Christoph Strobl + * @author Hyunsang Han */ class JpaRepositoryRegistrationAotProcessorUnitTests { @Test // GH-2628 void aotProcessorMustNotRegisterDomainTypes() { - GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(ClassName.OBJECT), - new InMemoryGeneratedFiles()); + GenerationContext ctx = createGenerationContext(); new JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor() .contribute(new DummyAotRepositoryContext(null) { @@ -79,8 +82,7 @@ public Set> getResolvedTypes() { @Test // GH-2628 void aotProcessorMustNotRegisterAnnotations() { - GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(ClassName.OBJECT), - new InMemoryGeneratedFiles()); + GenerationContext ctx = createGenerationContext(); new JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor() .contribute(new DummyAotRepositoryContext(null) { @@ -99,8 +101,7 @@ public Set> getResolvedAnnotations() { @Test // GH-3838 void repositoryProcessorShouldConsiderPersistenceManagedTypes() { - GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(ClassName.OBJECT), - new InMemoryGeneratedFiles()); + GenerationContext ctx = createGenerationContext(); GenericApplicationContext context = new GenericApplicationContext(); context.registerBean(PersistenceManagedTypes.class, () -> { @@ -126,12 +127,83 @@ public List getManagedPackages() { context.getEnvironment().getPropertySources() .addFirst(new MockPropertySource().withProperty(AotContext.GENERATED_REPOSITORIES_ENABLED, "true")); - JpaRepositoryContributor contributor = new JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor() - .contribute(new DummyAotRepositoryContext(context), ctx); + JpaRepositoryContributor contributor = createContributor(new DummyAotRepositoryContext(context), ctx); assertThat(contributor.getMetamodel().managedType(Person.class)).isNotNull(); } + @Test // GH-3899 + @SetSystemProperty(key = AotDetector.AOT_ENABLED, value = "true") + void repositoryProcessorShouldEnableAotRepositoriesByDefaultWhenAotIsEnabled() { + + GenerationContext ctx = createGenerationContext(); + GenericApplicationContext context = createApplicationContext(); + + JpaRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx); + + assertThat(contributor).isNotNull(); + } + + @Test // GH-3899 + @ClearSystemProperty(key = AotDetector.AOT_ENABLED) + void repositoryProcessorShouldNotEnableAotRepositoriesByDefaultWhenAotIsDisabled() { + + GenerationContext ctx = createGenerationContext(); + GenericApplicationContext context = createApplicationContext(); + + JpaRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx); + + assertThat(contributor).isNull(); + } + + @Test // GH-3899 + @SetSystemProperty(key = AotDetector.AOT_ENABLED, value = "true") + @SetSystemProperty(key = AotContext.GENERATED_REPOSITORIES_ENABLED, value = "false") + void repositoryProcessorShouldRespectExplicitRepositoryEnabledProperty() { + + GenerationContext ctx = createGenerationContext(); + GenericApplicationContext context = createApplicationContext(); + + JpaRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx); + + assertThat(contributor).isNull(); + } + + @Test // GH-3899 + @SetSystemProperty(key = AotContext.GENERATED_REPOSITORIES_ENABLED, value = "true") + void repositoryProcessorShouldEnableWhenExplicitlySetToTrue() { + + GenerationContext ctx = createGenerationContext(); + GenericApplicationContext context = createApplicationContext(); + + JpaRepositoryContributor contributor = createContributorWithPersonTypes(context, ctx); + + assertThat(contributor).isNotNull(); + } + + private GenerationContext createGenerationContext() { + return new DefaultGenerationContext(new ClassNameGenerator(ClassName.OBJECT), + new InMemoryGeneratedFiles()); + } + + private GenericApplicationContext createApplicationContext() { + return new GenericApplicationContext(); + } + + private JpaRepositoryContributor createContributor(AotRepositoryContext repositoryContext, GenerationContext ctx) { + return new JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor() + .contribute(repositoryContext, ctx); + } + + private JpaRepositoryContributor createContributorWithPersonTypes(GenericApplicationContext context, GenerationContext ctx) { + return createContributor(new DummyAotRepositoryContext(context) { + @Override + public Set> getResolvedTypes() { + return Collections.singleton(Person.class); + } + }, ctx); + } + @Entity static class Person { @Id Long id; diff --git a/src/main/antora/modules/ROOT/pages/jpa/aot.adoc b/src/main/antora/modules/ROOT/pages/jpa/aot.adoc index e8d2d4a1a8..67fce33498 100644 --- a/src/main/antora/modules/ROOT/pages/jpa/aot.adoc +++ b/src/main/antora/modules/ROOT/pages/jpa/aot.adoc @@ -44,7 +44,12 @@ Do not use them directly in your code as generation and implementation details m === 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. -It is also possible to use those optimizations on the JVM by setting the `spring.aot.enabled` and `spring.aot.repositories.enabled` properties to `true`. +When AOT is enabled (either for native compilation or by setting `spring.aot.enabled=true`), AOT repositories are automatically enabled by default. + +You can explicitly control AOT repository generation by setting the `spring.aot.repositories.enabled` property: + +* `spring.aot.repositories.enabled=true` - Explicitly enable AOT repositories +* `spring.aot.repositories.enabled=false` - Disable AOT repositories even when AOT is enabled AOT repositories contribute configuration changes to the actual repository bean registration to register the generated repository fragment.