Skip to content

Commit 36e60d8

Browse files
committed
Repository type preparation now only expands type variables declared in FactoryBean.
Related: GH-3074
1 parent f2608f6 commit 36e60d8

File tree

2 files changed

+59
-10
lines changed

2 files changed

+59
-10
lines changed

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

+11-10
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.springframework.core.metrics.StartupStep;
5050
import org.springframework.data.repository.core.RepositoryMetadata;
5151
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
52+
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
5253
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
5354
import org.springframework.data.util.ReflectionUtils;
5455
import org.springframework.lang.Nullable;
@@ -339,22 +340,22 @@ private ResolvableType getRepositoryInterface(RepositoryConfiguration<?> configu
339340
return null;
340341
}
341342

342-
TypeVariable<?>[] variables = factoryBean.getTypeParameters();
343-
int numberOfGenerics = variables.length;
344343
RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);
344+
List<Class<?>> types = List.of(repositoryInterface, metadata.getDomainType(), metadata.getIdType());
345345

346-
ResolvableType[] generics = new ResolvableType[numberOfGenerics];
347-
generics[0] = ResolvableType.forClass(repositoryInterface);
348-
generics[1] = ResolvableType.forClass(metadata.getDomainType());
349-
generics[2] = ResolvableType.forClass(metadata.getIdType());
346+
ResolvableType factoryBeanType = ResolvableType.forClass(RepositoryFactoryBeanSupport.class, factoryBean);
347+
ResolvableType[] factoryGenerics = factoryBeanType.getGenerics();
350348

351-
if (numberOfGenerics > 3) {
352-
for (int i = 3; i < numberOfGenerics; i++) {
353-
generics[i] = ResolvableType.forType(variables[0]);
349+
for (int i = 0; i < factoryGenerics.length; i++) {
350+
351+
ResolvableType parameter = factoryGenerics[i];
352+
353+
if (parameter.getType() instanceof TypeVariable<?> && i < types.size()) {
354+
factoryGenerics[i] = ResolvableType.forClass(types.get(i));
354355
}
355356
}
356357

357-
return ResolvableType.forClassWithGenerics(factoryBean, generics);
358+
return ResolvableType.forClassWithGenerics(factoryBean, factoryGenerics);
358359
}
359360

360361
/**

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

+48
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
import static org.assertj.core.api.Assertions.*;
1919

20+
import java.util.List;
21+
import java.util.Optional;
22+
import java.util.UUID;
23+
2024
import org.junit.jupiter.api.Test;
2125
import org.junit.jupiter.api.extension.ExtendWith;
2226
import org.mockito.Mockito;
@@ -26,6 +30,8 @@
2630
import org.springframework.aop.framework.Advised;
2731
import org.springframework.aot.hint.RuntimeHints;
2832
import org.springframework.beans.factory.ListableBeanFactory;
33+
import org.springframework.beans.factory.config.BeanDefinition;
34+
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
2935
import org.springframework.beans.factory.support.RootBeanDefinition;
3036
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
3137
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -37,13 +43,16 @@
3743
import org.springframework.core.metrics.ApplicationStartup;
3844
import org.springframework.core.type.AnnotationMetadata;
3945
import org.springframework.core.type.StandardAnnotationMetadata;
46+
import org.springframework.data.mapping.Person;
47+
import org.springframework.data.repository.Repository;
4048
import org.springframework.data.repository.config.RepositoryConfigurationDelegate.LazyRepositoryInjectionPointResolver;
4149
import org.springframework.data.repository.config.annotated.MyAnnotatedRepository;
4250
import org.springframework.data.repository.config.annotated.MyAnnotatedRepositoryImpl;
4351
import org.springframework.data.repository.config.annotated.MyFragmentImpl;
4452
import org.springframework.data.repository.config.excluded.MyOtherRepositoryImpl;
4553
import org.springframework.data.repository.config.stereotype.MyStereotypeRepository;
4654
import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean;
55+
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
4756
import org.springframework.data.repository.sample.AddressRepository;
4857
import org.springframework.data.repository.sample.AddressRepositoryClient;
4958
import org.springframework.data.repository.sample.ProductRepository;
@@ -279,4 +288,43 @@ protected String getModulePrefix() {
279288
return "commons";
280289
}
281290
}
291+
292+
@Test // GH-3074
293+
void registersGenericsForConstrainingRepositoryFactoryBean() {
294+
295+
AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class);
296+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
297+
298+
RepositoryConfigurationSource source = new AnnotationRepositoryConfigurationSource(metadata,
299+
EnableRepositories.class, context, context.getEnvironment(),
300+
context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()) {
301+
302+
@Override
303+
public Optional<String> getRepositoryFactoryBeanClassName() {
304+
return Optional.of(IdConstrainingRepositoryFactoryBean.class.getName());
305+
}
306+
};
307+
308+
RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(source, context,
309+
context.getEnvironment());
310+
311+
List<BeanComponentDefinition> repositories = delegate.registerRepositoriesIn(context, extension);
312+
313+
assertThat(repositories).hasSize(1).element(0)
314+
.extracting(BeanComponentDefinition::getBeanDefinition)
315+
.extracting(BeanDefinition::getResolvableType)
316+
.satisfies(it -> {
317+
assertThat(it.getGenerics()).hasSize(2);
318+
assertThat(it.getGeneric(0).resolve()).isEqualTo(MyAnnotatedRepository.class);
319+
assertThat(it.getGeneric(1).resolve()).isEqualTo(Person.class);
320+
});
321+
}
322+
323+
static abstract class IdConstrainingRepositoryFactoryBean<T extends Repository<S, UUID>, S>
324+
extends RepositoryFactoryBeanSupport<T, S, UUID> {
325+
326+
protected IdConstrainingRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
327+
super(repositoryInterface);
328+
}
329+
}
282330
}

0 commit comments

Comments
 (0)