Skip to content

Commit fe5e80e

Browse files
committed
Drop using FACTORY_BEAN_OBJECT_TYPE attribute entirely.
We now constantly use RootBeanDefinition.setBeanClass(…) (for the raw factory type) and ….setTargetType(…) to declare the full repository factory type including the user defined repository, domain and identifier type. Ticket: #2894.
1 parent d98eeef commit fe5e80e

File tree

3 files changed

+35
-53
lines changed

3 files changed

+35
-53
lines changed

src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java

+28-7
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@
2525

2626
import org.apache.commons.logging.Log;
2727
import org.apache.commons.logging.LogFactory;
28-
import org.springframework.beans.factory.FactoryBean;
2928
import org.springframework.beans.factory.config.BeanDefinition;
3029
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
3130
import org.springframework.beans.factory.config.DependencyDescriptor;
3231
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
33-
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3432
import org.springframework.beans.factory.support.AutowireCandidateResolver;
3533
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3634
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
3735
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3836
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
37+
import org.springframework.beans.factory.support.RootBeanDefinition;
3938
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
4039
import org.springframework.context.support.GenericApplicationContext;
40+
import org.springframework.core.ResolvableType;
4141
import org.springframework.core.env.Environment;
4242
import org.springframework.core.env.EnvironmentCapable;
4343
import org.springframework.core.env.StandardEnvironment;
@@ -46,6 +46,8 @@
4646
import org.springframework.core.log.LogMessage;
4747
import org.springframework.core.metrics.ApplicationStartup;
4848
import org.springframework.core.metrics.StartupStep;
49+
import org.springframework.data.repository.core.RepositoryMetadata;
50+
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
4951
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
5052
import org.springframework.data.util.ReflectionUtils;
5153
import org.springframework.lang.Nullable;
@@ -70,7 +72,6 @@ public class RepositoryConfigurationDelegate {
7072
private static final String REPOSITORY_REGISTRATION = "Spring Data %s - Registering repository: %s - Interface: %s - Factory: %s";
7173
private static final String MULTIPLE_MODULES = "Multiple Spring Data modules found, entering strict repository configuration mode";
7274
private static final String NON_DEFAULT_AUTOWIRE_CANDIDATE_RESOLVER = "Non-default AutowireCandidateResolver (%s) detected. Skipping the registration of LazyRepositoryInjectionPointResolver. Lazy repository injection will not be working";
73-
private static final String FACTORY_BEAN_OBJECT_TYPE = FactoryBean.OBJECT_TYPE_ATTRIBUTE;
7475

7576
private static final Log logger = LogFactory.getLog(RepositoryConfigurationDelegate.class);
7677

@@ -183,9 +184,9 @@ public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegist
183184
extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
184185
}
185186

186-
AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
187+
RootBeanDefinition beanDefinition = (RootBeanDefinition) definitionBuilder.getBeanDefinition();
187188

188-
beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, getRepositoryInterface(configuration));
189+
beanDefinition.setTargetType(getRepositoryInterface(configuration));
189190
beanDefinition.setResourceDescription(configuration.getResourceDescription());
190191

191192
String beanName = configurationSource.generateBeanName(beanDefinition);
@@ -316,14 +317,34 @@ private static ApplicationStartup getStartup(BeanDefinitionRegistry registry) {
316317
* @return can be {@literal null}.
317318
*/
318319
@Nullable
319-
private Class<?> getRepositoryInterface(RepositoryConfiguration<?> configuration) {
320+
private ResolvableType getRepositoryInterface(RepositoryConfiguration<?> configuration) {
320321

321322
String interfaceName = configuration.getRepositoryInterface();
322323
ClassLoader classLoader = resourceLoader.getClassLoader() == null
323324
? ClassUtils.getDefaultClassLoader()
324325
: resourceLoader.getClassLoader();
325326

326-
return ReflectionUtils.loadIfPresent(interfaceName, classLoader);
327+
classLoader = classLoader != null ? classLoader : getClass().getClassLoader();
328+
329+
Class<?> repositoryInterface = ReflectionUtils.loadIfPresent(interfaceName, classLoader);
330+
Class<?> factoryBean = ReflectionUtils.loadIfPresent(configuration.getRepositoryFactoryBeanClassName(),
331+
classLoader);
332+
RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);
333+
334+
int numberOfGenerics = factoryBean.getTypeParameters().length;
335+
336+
Class<?>[] generics = new Class<?>[numberOfGenerics];
337+
generics[0] = metadata.getRepositoryInterface();
338+
generics[1] = metadata.getDomainType();
339+
generics[2] = metadata.getIdType();
340+
341+
if (numberOfGenerics > 3) {
342+
for (int i = 3; i < numberOfGenerics; i++) {
343+
generics[i] = Object.class;
344+
}
345+
}
346+
347+
return ResolvableType.forClassWithGenerics(factoryBean, generics);
327348
}
328349

329350
/**

src/main/java/org/springframework/data/repository/config/RepositoryRegistrationAotContribution.java

-42
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,17 @@
3232
import org.springframework.aot.generate.GenerationContext;
3333
import org.springframework.aot.hint.MemberCategory;
3434
import org.springframework.aot.hint.TypeReference;
35-
import org.springframework.beans.factory.FactoryBean;
3635
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
3736
import org.springframework.beans.factory.aot.BeanRegistrationCode;
3837
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3938
import org.springframework.beans.factory.support.RegisteredBean;
40-
import org.springframework.beans.factory.support.RootBeanDefinition;
4139
import org.springframework.core.DecoratingProxy;
42-
import org.springframework.core.ResolvableType;
4340
import org.springframework.core.annotation.AnnotationUtils;
4441
import org.springframework.data.aot.AotContext;
4542
import org.springframework.data.projection.EntityProjectionIntrospector;
4643
import org.springframework.data.projection.TargetAware;
4744
import org.springframework.data.repository.Repository;
4845
import org.springframework.data.repository.core.RepositoryInformation;
49-
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
5046
import org.springframework.data.repository.core.support.RepositoryFragment;
5147
import org.springframework.data.util.QTypeContributor;
5248
import org.springframework.data.util.TypeContributor;
@@ -152,8 +148,6 @@ public RepositoryRegistrationAotContribution forBean(RegisteredBean repositoryBe
152148

153149
this.repositoryContext = buildAotRepositoryContext(repositoryBean, repositoryMetadata);
154150

155-
enhanceRepositoryBeanDefinition(repositoryBean, repositoryMetadata, this.repositoryContext);
156-
157151
return this;
158152
}
159153

@@ -203,44 +197,12 @@ private RepositoryInformation resolveRepositoryInformation(RepositoryConfigurati
203197
return RepositoryBeanDefinitionReader.readRepositoryInformation(repositoryMetadata, getBeanFactory());
204198
}
205199

206-
/**
207-
* Helps the AOT processing render the {@link FactoryBean} type correctly that is used to tell the outcome of the
208-
* {@link FactoryBean}. We just need to set the target {@link Repository} {@link Class type} of the
209-
* {@link RepositoryFactoryBeanSupport} while keeping the actual ID and DomainType set to {@link Object}. If the
210-
* generic type signature does not match, then we do not try to resolve and remap the types, but rather set the
211-
* {@literal factoryBeanObjectType} attribute on the {@link RootBeanDefinition}.
212-
*/
213-
protected void enhanceRepositoryBeanDefinition(RegisteredBean repositoryBean,
214-
RepositoryConfiguration<?> repositoryMetadata, AotRepositoryContext repositoryContext) {
215-
216-
logTrace(String.format("Enhancing repository factory bean definition [%s]", repositoryBean.getBeanName()));
217-
218-
Class<?> repositoryFactoryBeanType = repositoryContext
219-
.introspectType(repositoryMetadata.getRepositoryFactoryBeanClassName()).resolveType()
220-
.orElse(RepositoryFactoryBeanSupport.class);
221-
222-
ResolvableType resolvedRepositoryFactoryBeanType = ResolvableType.forClass(repositoryFactoryBeanType);
223-
224-
RootBeanDefinition repositoryBeanDefinition = repositoryBean.getMergedBeanDefinition();
225-
226-
if (isRepositoryWithTypeParameters(resolvedRepositoryFactoryBeanType)) {
227-
repositoryBeanDefinition.setTargetType(ResolvableType.forClassWithGenerics(repositoryFactoryBeanType,
228-
repositoryContext.getRepositoryInformation().getRepositoryInterface(), Object.class, Object.class));
229-
} else {
230-
repositoryBeanDefinition.setTargetType(resolvedRepositoryFactoryBeanType);
231-
repositoryBeanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE,
232-
repositoryContext.getRepositoryInformation().getRepositoryInterface());
233-
}
234-
}
235-
236200
/**
237201
* {@link BiConsumer Callback} for data module specific contributions.
238202
*
239203
* @param moduleContribution {@link BiConsumer} used by data modules to submit contributions; can be {@literal null}.
240204
* @return this.
241205
*/
242-
243-
@SuppressWarnings("unused")
244206
public RepositoryRegistrationAotContribution withModuleContribution(
245207
@Nullable BiConsumer<AotRepositoryContext, GenerationContext> moduleContribution) {
246208
this.moduleContribution = moduleContribution;
@@ -385,8 +347,4 @@ static boolean isJavaOrPrimitiveType(Class<?> type) {
385347
public Predicate<Class<?>> typeFilter() { // like only document ones. // TODO: As in MongoDB?
386348
return it -> true;
387349
}
388-
389-
private static boolean isRepositoryWithTypeParameters(ResolvableType type) {
390-
return type.getGenerics().length == 3;
391-
}
392350
}

src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
import org.mockito.quality.Strictness;
2626
import org.springframework.aop.framework.Advised;
2727
import org.springframework.aot.hint.RuntimeHints;
28-
import org.springframework.beans.factory.FactoryBean;
2928
import org.springframework.beans.factory.ListableBeanFactory;
29+
import org.springframework.beans.factory.support.RootBeanDefinition;
3030
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
3131
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3232
import org.springframework.context.annotation.ComponentScan;
@@ -76,10 +76,13 @@ void registersRepositoryBeanNameAsAttribute() {
7676
for (var definition : delegate.registerRepositoriesIn(context, extension)) {
7777

7878
var beanDefinition = definition.getBeanDefinition();
79-
var attribute = beanDefinition.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE);
8079

81-
assertThat(attribute).isInstanceOfSatisfying(Class.class, it -> {
82-
assertThat(it.getName()).endsWith("Repository");
80+
assertThat(beanDefinition).isInstanceOfSatisfying(RootBeanDefinition.class, it -> {
81+
82+
var type = it.getTargetType();
83+
84+
assertThat(type).isNotNull();
85+
assertThat(type.getName()).endsWith("FactoryBean");
8386
});
8487
}
8588
}

0 commit comments

Comments
 (0)