diff --git a/pom.xml b/pom.xml
index 5ba0fde025..18457886da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-jpa-parent
- 3.0.0-SNAPSHOT
+ 3.0.x-GH-2628-SNAPSHOT
pom
Spring Data JPA Parent
diff --git a/spring-data-envers/pom.xml b/spring-data-envers/pom.xml
index 540834bb60..6e6be0e0e7 100755
--- a/spring-data-envers/pom.xml
+++ b/spring-data-envers/pom.xml
@@ -5,12 +5,12 @@
org.springframework.data
spring-data-envers
- 3.0.0-SNAPSHOT
+ 3.0.x-GH-2628-SNAPSHOT
org.springframework.data
spring-data-jpa-parent
- 3.0.0-SNAPSHOT
+ 3.0.x-GH-2628-SNAPSHOT
../pom.xml
diff --git a/spring-data-jpa-distribution/pom.xml b/spring-data-jpa-distribution/pom.xml
index bba8571672..724b2f2eec 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
- 3.0.0-SNAPSHOT
+ 3.0.x-GH-2628-SNAPSHOT
../pom.xml
diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml
index 3ad9c39a2a..e995d2b343 100644
--- a/spring-data-jpa/pom.xml
+++ b/spring-data-jpa/pom.xml
@@ -6,7 +6,7 @@
org.springframework.data
spring-data-jpa
- 3.0.0-SNAPSHOT
+ 3.0.x-GH-2628-SNAPSHOT
Spring Data JPA
Spring Data module for JPA repositories.
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-jpa-parent
- 3.0.0-SNAPSHOT
+ 3.0.x-GH-2628-SNAPSHOT
../pom.xml
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 07550f533c..e06e6abb0f 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
@@ -33,6 +33,8 @@
import java.util.Optional;
import java.util.Set;
+import org.springframework.aot.generate.GenerationContext;
+import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -44,6 +46,8 @@
import org.springframework.core.io.ResourceLoader;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
+import org.springframework.data.aot.AotRepositoryContext;
+import org.springframework.data.aot.RepositoryRegistrationAotProcessor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.DefaultJpaContext;
import org.springframework.data.jpa.repository.support.EntityManagerBeanDefinitionRegistrarPostProcessor;
@@ -118,6 +122,11 @@ public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSo
builder.addPropertyReference("mappingContext", JPA_MAPPING_CONTEXT_BEAN_NAME);
}
+ @Override
+ public Class extends BeanRegistrationAotProcessor> getRepositoryAotProcessor() {
+ return JpaRepositoryRegistrationAotProcessor.class;
+ }
+
/**
* XML configurations do not support {@link Character} values. This method catches the exception thrown and returns an
* {@link Optional#empty()} instead.
@@ -285,4 +294,18 @@ static boolean isActive(@Nullable ClassLoader classLoader) {
.anyMatch(agentClass -> ClassUtils.isPresent(agentClass, classLoader));
}
}
+
+ /**
+ * A {@link RepositoryRegistrationAotProcessor} implementation that maintains aot repository setup but skips domain
+ * type inspection which is handled by the core framework support for
+ * {@link org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes}.
+ *
+ * @since 3.0
+ */
+ public static class JpaRepositoryRegistrationAotProcessor extends RepositoryRegistrationAotProcessor {
+
+ protected void contribute(AotRepositoryContext repositoryContext, GenerationContext generationContext) {
+ // don't register domain types nor annotations.
+ }
+ }
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java
index d9d62f8da4..a3e4ac9eab 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java
@@ -18,19 +18,18 @@
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
-import java.util.Arrays;
-import java.util.Collections;
-
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.metamodel.Metamodel;
+import java.util.Arrays;
+import java.util.Collections;
+
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -141,6 +140,13 @@ public Class> loadClass(String name) throws ClassNotFoundException {
assertThat(classLoader).isNotInstanceOf(InspectionClassLoader.class);
}
+ @Test // GH-2628
+ void exposesJpaAotProcessor() {
+
+ assertThat(new JpaRepositoryConfigExtension().getRepositoryAotProcessor())
+ .isEqualTo(JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor.class);
+ }
+
private void assertOnlyOnePersistenceAnnotationBeanPostProcessorRegistered(DefaultListableBeanFactory factory,
String expectedBeanName) {
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
new file mode 100644
index 0000000000..5204de044c
--- /dev/null
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository.config;
+
+import static org.assertj.core.api.Assertions.*;
+
+import jakarta.persistence.Entity;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.aot.generate.ClassNameGenerator;
+import org.springframework.aot.generate.DefaultGenerationContext;
+import org.springframework.aot.generate.GenerationContext;
+import org.springframework.aot.generate.InMemoryGeneratedFiles;
+import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.core.annotation.MergedAnnotation;
+import org.springframework.data.aot.AotRepositoryContext;
+import org.springframework.data.repository.core.RepositoryInformation;
+
+/**
+ * @author Christoph Strobl
+ */
+class JpaRepositoryRegistrationAotProcessorUnitTests {
+
+ @Test // GH-2628
+ void aotProcessorMustNotRegisterDomainTypes() {
+
+ GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(Object.class),
+ new InMemoryGeneratedFiles());
+
+ new JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor()
+ .contribute(new DummyAotRepositoryContext() {
+ @Override
+ public Set> getResolvedTypes() {
+ return Collections.singleton(Person.class);
+ }
+ }, ctx);
+
+ assertThat(RuntimeHintsPredicates.reflection().onType(Person.class)).rejects(ctx.getRuntimeHints());
+ }
+
+ @Test // GH-2628
+ void aotProcessorMustNotRegisterAnnotations() {
+
+ GenerationContext ctx = new DefaultGenerationContext(new ClassNameGenerator(Object.class),
+ new InMemoryGeneratedFiles());
+
+ new JpaRepositoryConfigExtension.JpaRepositoryRegistrationAotProcessor()
+ .contribute(new DummyAotRepositoryContext() {
+
+ @Override
+ public Set> getResolvedAnnotations() {
+
+ MergedAnnotation mergedAnnotation = MergedAnnotation.of(Entity.class);
+ return Set.of(mergedAnnotation);
+ }
+ }, ctx);
+
+ assertThat(RuntimeHintsPredicates.reflection().onType(Entity.class)).rejects(ctx.getRuntimeHints());
+ }
+
+ static class Person {}
+
+ static class DummyAotRepositoryContext implements AotRepositoryContext {
+
+ @Override
+ public String getBeanName() {
+ return "jpaRepository";
+ }
+
+ @Override
+ public Set getBasePackages() {
+ return Collections.singleton(this.getClass().getPackageName());
+ }
+
+ @Override
+ public Set> getIdentifyingAnnotations() {
+ return Collections.singleton(Entity.class);
+ }
+
+ @Override
+ public RepositoryInformation getRepositoryInformation() {
+ return null;
+ }
+
+ @Override
+ public Set> getResolvedAnnotations() {
+ return null;
+ }
+
+ @Override
+ public Set> getResolvedTypes() {
+ return null;
+ }
+
+ @Override
+ public ConfigurableListableBeanFactory getBeanFactory() {
+ return null;
+ }
+
+ @Override
+ public TypeIntrospector introspectType(String typeName) {
+ return null;
+ }
+
+ @Override
+ public IntrospectedBeanDefinition introspectBeanDefinition(String beanName) {
+ return null;
+ }
+ }
+}