Skip to content

Commit 83330da

Browse files
committed
Make target type of bean definition more accurate
Now generics of RepositoryFactoryBean will use generics from Repository instead of Object.class if possible
1 parent 3aba5eb commit 83330da

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

Diff for: src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java

+21-4
Original file line numberDiff line numberDiff line change
@@ -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.Repository;
50+
import org.springframework.data.repository.RepositoryDefinition;
4951
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
5052
import org.springframework.data.util.ReflectionUtils;
5153
import org.springframework.lang.Nullable;
@@ -64,6 +66,7 @@
6466
* @author Mark Paluch
6567
* @author Christoph Strobl
6668
* @author John Blum
69+
* @author Yanming Zhou
6770
*/
6871
public class RepositoryConfigurationDelegate {
6972

@@ -330,12 +333,26 @@ private ResolvableType getRepositoryInterface(RepositoryConfiguration<?> configu
330333

331334
int numberOfGenerics = factoryBean.getTypeParameters().length;
332335

333-
Class<?>[] generics = new Class<?>[numberOfGenerics];
334-
generics[0] = repositoryInterface;
336+
ResolvableType[] generics = new ResolvableType[numberOfGenerics];
337+
generics[0] = ResolvableType.forClass(repositoryInterface);
335338

336339
if (numberOfGenerics > 1) {
337-
for (int i = 1; i < numberOfGenerics; i++) {
338-
generics[i] = Object.class;
340+
ResolvableType[] typeArguments;
341+
if (repositoryInterface.isAnnotationPresent(RepositoryDefinition.class)) {
342+
RepositoryDefinition rd = repositoryInterface.getAnnotation(RepositoryDefinition.class);
343+
typeArguments = new ResolvableType[] { ResolvableType.forClass(rd.domainClass()), ResolvableType.forClass(rd.idClass()) };
344+
}
345+
else {
346+
typeArguments = generics[0].as(Repository.class).getGenerics();
347+
}
348+
349+
if (typeArguments.length == numberOfGenerics - 1) {
350+
System.arraycopy(typeArguments, 0, generics, 1, numberOfGenerics - 1);
351+
}
352+
else {
353+
for (int i = 1; i < numberOfGenerics; i++) {
354+
generics[i] = ResolvableType.forClass(Object.class);
355+
}
339356
}
340357
}
341358

Diff for: src/test/java/org/springframework/data/repository/config/RepositoryConfigurationDelegateUnitTests.java

+40
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@
2626
import org.springframework.aop.framework.Advised;
2727
import org.springframework.aot.hint.RuntimeHints;
2828
import org.springframework.beans.factory.ListableBeanFactory;
29+
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
2930
import org.springframework.beans.factory.support.RootBeanDefinition;
3031
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
3132
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
3233
import org.springframework.context.annotation.ComponentScan;
3334
import org.springframework.context.annotation.ComponentScan.Filter;
3435
import org.springframework.context.annotation.FilterType;
3536
import org.springframework.context.support.GenericApplicationContext;
37+
import org.springframework.core.ResolvableType;
3638
import org.springframework.core.env.StandardEnvironment;
3739
import org.springframework.core.metrics.ApplicationStartup;
3840
import org.springframework.core.type.AnnotationMetadata;
@@ -46,13 +48,19 @@
4648
import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean;
4749
import org.springframework.data.repository.sample.AddressRepository;
4850
import org.springframework.data.repository.sample.AddressRepositoryClient;
51+
import org.springframework.data.repository.sample.Product;
4952
import org.springframework.data.repository.sample.ProductRepository;
53+
import org.springframework.data.repository.sample.SampleAnnotatedRepository;
54+
55+
import java.io.Serializable;
56+
import java.util.List;
5057

5158
/**
5259
* Unit tests for {@link RepositoryConfigurationDelegate}.
5360
*
5461
* @author Oliver Gierke
5562
* @author Mark Paluch
63+
* @author Yanming Zhou
5664
* @soundtrack Richard Spaven - Tribute (Whole Other*)
5765
*/
5866
@ExtendWith(MockitoExtension.class)
@@ -87,6 +95,38 @@ void registersRepositoryBeanNameAsAttribute() {
8795
}
8896
}
8997

98+
@Test
99+
void registersAccurateTargetTypeOfBeanDefinition() {
100+
101+
var environment = new StandardEnvironment();
102+
var context = new GenericApplicationContext();
103+
104+
RepositoryConfigurationSource configSource = new AnnotationRepositoryConfigurationSource(
105+
new StandardAnnotationMetadata(TestConfig.class, true), EnableRepositories.class, context, environment,
106+
context.getDefaultListableBeanFactory(), null);
107+
108+
var delegate = new RepositoryConfigurationDelegate(configSource, context, environment);
109+
List<BeanComponentDefinition> bcds = delegate.registerRepositoriesIn(context, extension);
110+
var productRepository = bcds.stream().filter(bcd ->
111+
bcd.getName().equals("productRepository")).map(BeanComponentDefinition::getBeanDefinition).findFirst();
112+
var sampleAnnotatedRepository = bcds.stream().filter(bcd ->
113+
bcd.getName().equals("sampleAnnotatedRepository")).map(BeanComponentDefinition::getBeanDefinition).findFirst();
114+
115+
assertThat(productRepository).isPresent().get().isInstanceOfSatisfying(RootBeanDefinition.class, it -> {
116+
ResolvableType[] generics = it.getResolvableType().getGenerics();
117+
assertThat(generics[0].resolve()).isSameAs(ProductRepository.class);
118+
assertThat(generics[1].resolve()).isSameAs(Product.class);
119+
assertThat(generics[2].resolve()).isSameAs(Long.class);
120+
});
121+
122+
assertThat(sampleAnnotatedRepository).isPresent().get().isInstanceOfSatisfying(RootBeanDefinition.class, it -> {
123+
ResolvableType[] generics = it.getResolvableType().getGenerics();
124+
assertThat(generics[0].resolve()).isSameAs(SampleAnnotatedRepository.class);
125+
assertThat(generics[1].resolve()).isSameAs(Object.class);
126+
assertThat(generics[2].resolve()).isSameAs(Serializable.class);
127+
});
128+
}
129+
90130
@Test // DATACMNS-1368
91131
void registersLazyAutowireCandidateResolver() {
92132
assertLazyRepositoryBeanSetup(LazyConfig.class);

0 commit comments

Comments
 (0)