Skip to content

Commit 98f20a4

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. Any other generics are simply filled with Object.class. Ticket: #2894.
1 parent d98eeef commit 98f20a4

File tree

3 files changed

+30
-53
lines changed

3 files changed

+30
-53
lines changed

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

+23-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;
@@ -70,7 +70,6 @@ public class RepositoryConfigurationDelegate {
7070
private static final String REPOSITORY_REGISTRATION = "Spring Data %s - Registering repository: %s - Interface: %s - Factory: %s";
7171
private static final String MULTIPLE_MODULES = "Multiple Spring Data modules found, entering strict repository configuration mode";
7272
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;
7473

7574
private static final Log logger = LogFactory.getLog(RepositoryConfigurationDelegate.class);
7675

@@ -183,9 +182,9 @@ public List<BeanComponentDefinition> registerRepositoriesIn(BeanDefinitionRegist
183182
extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource);
184183
}
185184

186-
AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition();
185+
RootBeanDefinition beanDefinition = (RootBeanDefinition) definitionBuilder.getBeanDefinition();
187186

188-
beanDefinition.setAttribute(FACTORY_BEAN_OBJECT_TYPE, getRepositoryInterface(configuration));
187+
beanDefinition.setTargetType(getRepositoryInterface(configuration));
189188
beanDefinition.setResourceDescription(configuration.getResourceDescription());
190189

191190
String beanName = configurationSource.generateBeanName(beanDefinition);
@@ -316,14 +315,31 @@ private static ApplicationStartup getStartup(BeanDefinitionRegistry registry) {
316315
* @return can be {@literal null}.
317316
*/
318317
@Nullable
319-
private Class<?> getRepositoryInterface(RepositoryConfiguration<?> configuration) {
318+
private ResolvableType getRepositoryInterface(RepositoryConfiguration<?> configuration) {
320319

321320
String interfaceName = configuration.getRepositoryInterface();
322321
ClassLoader classLoader = resourceLoader.getClassLoader() == null
323322
? ClassUtils.getDefaultClassLoader()
324323
: resourceLoader.getClassLoader();
325324

326-
return ReflectionUtils.loadIfPresent(interfaceName, classLoader);
325+
classLoader = classLoader != null ? classLoader : getClass().getClassLoader();
326+
327+
Class<?> repositoryInterface = ReflectionUtils.loadIfPresent(interfaceName, classLoader);
328+
Class<?> factoryBean = ReflectionUtils.loadIfPresent(configuration.getRepositoryFactoryBeanClassName(),
329+
classLoader);
330+
331+
int numberOfGenerics = factoryBean.getTypeParameters().length;
332+
333+
Class<?>[] generics = new Class<?>[numberOfGenerics];
334+
generics[0] = repositoryInterface;
335+
336+
if (numberOfGenerics > 1) {
337+
for (int i = 1; i < numberOfGenerics; i++) {
338+
generics[i] = Object.class;
339+
}
340+
}
341+
342+
return ResolvableType.forClassWithGenerics(factoryBean, generics);
327343
}
328344

329345
/**

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)