Repository type preparation now only expands type variables declared in FactoryBean.
Related: GH-3074
This commit is contained in:
@@ -49,6 +49,7 @@ import org.springframework.core.metrics.ApplicationStartup;
|
||||
import org.springframework.core.metrics.StartupStep;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.util.ReflectionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -339,22 +340,22 @@ public class RepositoryConfigurationDelegate {
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeVariable<?>[] variables = factoryBean.getTypeParameters();
|
||||
int numberOfGenerics = variables.length;
|
||||
RepositoryMetadata metadata = AbstractRepositoryMetadata.getMetadata(repositoryInterface);
|
||||
List<Class<?>> types = List.of(repositoryInterface, metadata.getDomainType(), metadata.getIdType());
|
||||
|
||||
ResolvableType[] generics = new ResolvableType[numberOfGenerics];
|
||||
generics[0] = ResolvableType.forClass(repositoryInterface);
|
||||
generics[1] = ResolvableType.forClass(metadata.getDomainType());
|
||||
generics[2] = ResolvableType.forClass(metadata.getIdType());
|
||||
ResolvableType factoryBeanType = ResolvableType.forClass(RepositoryFactoryBeanSupport.class, factoryBean);
|
||||
ResolvableType[] factoryGenerics = factoryBeanType.getGenerics();
|
||||
|
||||
if (numberOfGenerics > 3) {
|
||||
for (int i = 3; i < numberOfGenerics; i++) {
|
||||
generics[i] = ResolvableType.forType(variables[0]);
|
||||
for (int i = 0; i < factoryGenerics.length; i++) {
|
||||
|
||||
ResolvableType parameter = factoryGenerics[i];
|
||||
|
||||
if (parameter.getType() instanceof TypeVariable<?> && i < types.size()) {
|
||||
factoryGenerics[i] = ResolvableType.forClass(types.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return ResolvableType.forClassWithGenerics(factoryBean, generics);
|
||||
return ResolvableType.forClassWithGenerics(factoryBean, factoryGenerics);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,10 @@ package org.springframework.data.repository.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mockito;
|
||||
@@ -26,6 +30,8 @@ import org.mockito.quality.Strictness;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -37,6 +43,8 @@ import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.metrics.ApplicationStartup;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.mapping.Person;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.config.RepositoryConfigurationDelegate.LazyRepositoryInjectionPointResolver;
|
||||
import org.springframework.data.repository.config.annotated.MyAnnotatedRepository;
|
||||
import org.springframework.data.repository.config.annotated.MyAnnotatedRepositoryImpl;
|
||||
@@ -44,6 +52,7 @@ import org.springframework.data.repository.config.annotated.MyFragmentImpl;
|
||||
import org.springframework.data.repository.config.excluded.MyOtherRepositoryImpl;
|
||||
import org.springframework.data.repository.config.stereotype.MyStereotypeRepository;
|
||||
import org.springframework.data.repository.core.support.DummyRepositoryFactoryBean;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
import org.springframework.data.repository.sample.AddressRepository;
|
||||
import org.springframework.data.repository.sample.AddressRepositoryClient;
|
||||
import org.springframework.data.repository.sample.ProductRepository;
|
||||
@@ -279,4 +288,43 @@ class RepositoryConfigurationDelegateUnitTests {
|
||||
return "commons";
|
||||
}
|
||||
}
|
||||
|
||||
@Test // GH-3074
|
||||
void registersGenericsForConstrainingRepositoryFactoryBean() {
|
||||
|
||||
AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedBeanNamesConfig.class);
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
RepositoryConfigurationSource source = new AnnotationRepositoryConfigurationSource(metadata,
|
||||
EnableRepositories.class, context, context.getEnvironment(),
|
||||
context.getDefaultListableBeanFactory(), new AnnotationBeanNameGenerator()) {
|
||||
|
||||
@Override
|
||||
public Optional<String> getRepositoryFactoryBeanClassName() {
|
||||
return Optional.of(IdConstrainingRepositoryFactoryBean.class.getName());
|
||||
}
|
||||
};
|
||||
|
||||
RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(source, context,
|
||||
context.getEnvironment());
|
||||
|
||||
List<BeanComponentDefinition> repositories = delegate.registerRepositoriesIn(context, extension);
|
||||
|
||||
assertThat(repositories).hasSize(1).element(0)
|
||||
.extracting(BeanComponentDefinition::getBeanDefinition)
|
||||
.extracting(BeanDefinition::getResolvableType)
|
||||
.satisfies(it -> {
|
||||
assertThat(it.getGenerics()).hasSize(2);
|
||||
assertThat(it.getGeneric(0).resolve()).isEqualTo(MyAnnotatedRepository.class);
|
||||
assertThat(it.getGeneric(1).resolve()).isEqualTo(Person.class);
|
||||
});
|
||||
}
|
||||
|
||||
static abstract class IdConstrainingRepositoryFactoryBean<T extends Repository<S, UUID>, S>
|
||||
extends RepositoryFactoryBeanSupport<T, S, UUID> {
|
||||
|
||||
protected IdConstrainingRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
|
||||
super(repositoryInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user