Add support for BeanNameGenerator configuration in Enable…Repositories.
We now accept a dedicated BeanNameGenerator in our Enable…Repositories annotations to override the importBeanNameGenerator. Closes: #3082 Original Pull Request: #3083
This commit is contained in:
committed by
Christoph Strobl
parent
a115ee6a44
commit
a37a700b59
@@ -24,6 +24,7 @@ import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
|
||||
@@ -64,6 +65,7 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
|
||||
private static final String REPOSITORY_BASE_CLASS = "repositoryBaseClass";
|
||||
private static final String CONSIDER_NESTED_REPOSITORIES = "considerNestedRepositories";
|
||||
private static final String BOOTSTRAP_MODE = "bootstrapMode";
|
||||
private static final String BEAN_NAME_GENERATOR = "nameGenerator";
|
||||
|
||||
private final AnnotationMetadata configMetadata;
|
||||
private final AnnotationMetadata enableAnnotationMetadata;
|
||||
@@ -97,14 +99,15 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
|
||||
* @param resourceLoader must not be {@literal null}.
|
||||
* @param environment must not be {@literal null}.
|
||||
* @param registry must not be {@literal null}.
|
||||
* @param generator can be {@literal null}.
|
||||
* @param importBeanNameGenerator can be {@literal null}.
|
||||
*/
|
||||
public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class<? extends Annotation> annotation,
|
||||
ResourceLoader resourceLoader, Environment environment, BeanDefinitionRegistry registry,
|
||||
@Nullable BeanNameGenerator generator) {
|
||||
@Nullable BeanNameGenerator importBeanNameGenerator) {
|
||||
|
||||
super(environment, ConfigurationUtils.getRequiredClassLoader(resourceLoader), registry,
|
||||
defaultBeanNameGenerator(generator));
|
||||
configuredOrDefaultBeanNameGenerator(metadata, annotation,
|
||||
ConfigurationUtils.getRequiredClassLoader(resourceLoader), importBeanNameGenerator));
|
||||
|
||||
Assert.notNull(metadata, "Metadata must not be null");
|
||||
Assert.notNull(annotation, "Annotation must not be null");
|
||||
@@ -305,6 +308,24 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
|
||||
.anyMatch(it -> attributes.getAnnotationArray(it).length > 0);
|
||||
}
|
||||
|
||||
private static BeanNameGenerator configuredOrDefaultBeanNameGenerator(AnnotationMetadata metadata,
|
||||
Class<? extends Annotation> annotation, ClassLoader beanClassLoader,
|
||||
@Nullable BeanNameGenerator importBeanNameGenerator) {
|
||||
|
||||
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(annotation.getName());
|
||||
|
||||
if (annotationAttributes != null) {
|
||||
|
||||
BeanNameGenerator beanNameGenerator = getBeanNameGenerator(annotationAttributes, beanClassLoader);
|
||||
|
||||
if (beanNameGenerator != null) {
|
||||
return beanNameGenerator;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultBeanNameGenerator(importBeanNameGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link BeanNameGenerator} to use falling back to an {@link AnnotationBeanNameGenerator} if either the
|
||||
* given generator is {@literal null} or it's the one locally declared in {@link ConfigurationClassPostProcessor}'s
|
||||
@@ -321,4 +342,37 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
|
||||
? new AnnotationBeanNameGenerator() //
|
||||
: generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a configured {@link BeanNameGenerator}.
|
||||
*
|
||||
* @param beanClassLoader a class loader to load the configured {@link BeanNameGenerator} class in case it was
|
||||
* configured as String instead of a Class instance.
|
||||
* @return the bean name generator.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private static BeanNameGenerator getBeanNameGenerator(Map<String, Object> annotationAttributes,
|
||||
ClassLoader beanClassLoader) {
|
||||
|
||||
Object configuredBeanNameGenerator = annotationAttributes.get(BEAN_NAME_GENERATOR);
|
||||
|
||||
if (configuredBeanNameGenerator == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (configuredBeanNameGenerator instanceof String cbng) {
|
||||
try {
|
||||
configuredBeanNameGenerator = ClassUtils.forName(cbng, beanClassLoader);
|
||||
} catch (Exception o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
|
||||
if (configuredBeanNameGenerator != BeanNameGenerator.class) {
|
||||
return BeanUtils.instantiateClass((Class<? extends BeanNameGenerator>) configuredBeanNameGenerator);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ public interface RepositoryConfigurationSource {
|
||||
BootstrapMode getBootstrapMode();
|
||||
|
||||
/**
|
||||
* Returns a human readable description of the repository configuration source for error reporting purposes.
|
||||
* Returns a human-readable description of the repository configuration source for error reporting purposes.
|
||||
*
|
||||
* @return can be {@literal null}.
|
||||
* @since 2.3
|
||||
|
||||
@@ -24,7 +24,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
@@ -33,6 +35,8 @@ import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.config.basepackage.repo.PersonRepository;
|
||||
import org.springframework.data.repository.core.support.DummyRepositoryFactory;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AnnotationRepositoryConfigurationSource}.
|
||||
@@ -165,6 +169,17 @@ class AnnotationRepositoryConfigurationSourceUnitTests {
|
||||
.isThrownBy(() -> source.getRequiredAttribute("namedQueriesLocation", String.class));
|
||||
}
|
||||
|
||||
@Test // GH-3082
|
||||
void considerBeanNameGenerator() {
|
||||
|
||||
RootBeanDefinition bd = new RootBeanDefinition(DummyRepositoryFactory.class);
|
||||
bd.getConstructorArgumentValues().addGenericArgumentValue(PersonRepository.class);
|
||||
|
||||
assertThat(getConfigSource(ConfigurationWithBeanNameGenerator.class).generateBeanName(bd))
|
||||
.isEqualTo("org.springframework.data.repository.config.basepackage.repo.PersonRepository");
|
||||
assertThat(getConfigSource(DefaultConfiguration.class).generateBeanName(bd)).isEqualTo("personRepository");
|
||||
}
|
||||
|
||||
private AnnotationRepositoryConfigurationSource getConfigSource(Class<?> type) {
|
||||
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(type, true);
|
||||
@@ -186,6 +201,9 @@ class AnnotationRepositoryConfigurationSourceUnitTests {
|
||||
@EnableRepositories(excludeFilters = { @Filter(Primary.class) })
|
||||
static class ConfigurationWithExplicitFilter {}
|
||||
|
||||
@EnableRepositories(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
|
||||
static class ConfigurationWithBeanNameGenerator {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface SampleAnnotation {
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
@@ -43,6 +44,8 @@ public @interface EnableRepositories {
|
||||
|
||||
Class<?> repositoryBaseClass() default PagingAndSortingRepository.class;
|
||||
|
||||
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
|
||||
|
||||
String namedQueriesLocation() default "";
|
||||
|
||||
String repositoryImplementationPostfix() default "Impl";
|
||||
|
||||
Reference in New Issue
Block a user