Skip to content

Commit a37a700

Browse files
mp911dechristophstrobl
authored andcommitted
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
1 parent a115ee6 commit a37a700

File tree

4 files changed

+79
-4
lines changed

4 files changed

+79
-4
lines changed

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

+57-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.function.Function;
2525
import java.util.stream.Stream;
2626

27+
import org.springframework.beans.BeanUtils;
2728
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2829
import org.springframework.beans.factory.support.BeanNameGenerator;
2930
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
@@ -64,6 +65,7 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
6465
private static final String REPOSITORY_BASE_CLASS = "repositoryBaseClass";
6566
private static final String CONSIDER_NESTED_REPOSITORIES = "considerNestedRepositories";
6667
private static final String BOOTSTRAP_MODE = "bootstrapMode";
68+
private static final String BEAN_NAME_GENERATOR = "nameGenerator";
6769

6870
private final AnnotationMetadata configMetadata;
6971
private final AnnotationMetadata enableAnnotationMetadata;
@@ -97,14 +99,15 @@ public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Clas
9799
* @param resourceLoader must not be {@literal null}.
98100
* @param environment must not be {@literal null}.
99101
* @param registry must not be {@literal null}.
100-
* @param generator can be {@literal null}.
102+
* @param importBeanNameGenerator can be {@literal null}.
101103
*/
102104
public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class<? extends Annotation> annotation,
103105
ResourceLoader resourceLoader, Environment environment, BeanDefinitionRegistry registry,
104-
@Nullable BeanNameGenerator generator) {
106+
@Nullable BeanNameGenerator importBeanNameGenerator) {
105107

106108
super(environment, ConfigurationUtils.getRequiredClassLoader(resourceLoader), registry,
107-
defaultBeanNameGenerator(generator));
109+
configuredOrDefaultBeanNameGenerator(metadata, annotation,
110+
ConfigurationUtils.getRequiredClassLoader(resourceLoader), importBeanNameGenerator));
108111

109112
Assert.notNull(metadata, "Metadata must not be null");
110113
Assert.notNull(annotation, "Annotation must not be null");
@@ -305,6 +308,24 @@ private static boolean hasExplicitFilters(AnnotationAttributes attributes) {
305308
.anyMatch(it -> attributes.getAnnotationArray(it).length > 0);
306309
}
307310

311+
private static BeanNameGenerator configuredOrDefaultBeanNameGenerator(AnnotationMetadata metadata,
312+
Class<? extends Annotation> annotation, ClassLoader beanClassLoader,
313+
@Nullable BeanNameGenerator importBeanNameGenerator) {
314+
315+
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(annotation.getName());
316+
317+
if (annotationAttributes != null) {
318+
319+
BeanNameGenerator beanNameGenerator = getBeanNameGenerator(annotationAttributes, beanClassLoader);
320+
321+
if (beanNameGenerator != null) {
322+
return beanNameGenerator;
323+
}
324+
}
325+
326+
return defaultBeanNameGenerator(importBeanNameGenerator);
327+
}
328+
308329
/**
309330
* Returns the {@link BeanNameGenerator} to use falling back to an {@link AnnotationBeanNameGenerator} if either the
310331
* given generator is {@literal null} or it's the one locally declared in {@link ConfigurationClassPostProcessor}'s
@@ -321,4 +342,37 @@ private static BeanNameGenerator defaultBeanNameGenerator(@Nullable BeanNameGene
321342
? new AnnotationBeanNameGenerator() //
322343
: generator;
323344
}
345+
346+
/**
347+
* Obtain a configured {@link BeanNameGenerator}.
348+
*
349+
* @param beanClassLoader a class loader to load the configured {@link BeanNameGenerator} class in case it was
350+
* configured as String instead of a Class instance.
351+
* @return the bean name generator.
352+
*/
353+
@Nullable
354+
@SuppressWarnings("unchecked")
355+
private static BeanNameGenerator getBeanNameGenerator(Map<String, Object> annotationAttributes,
356+
ClassLoader beanClassLoader) {
357+
358+
Object configuredBeanNameGenerator = annotationAttributes.get(BEAN_NAME_GENERATOR);
359+
360+
if (configuredBeanNameGenerator == null) {
361+
return null;
362+
}
363+
364+
if (configuredBeanNameGenerator instanceof String cbng) {
365+
try {
366+
configuredBeanNameGenerator = ClassUtils.forName(cbng, beanClassLoader);
367+
} catch (Exception o_O) {
368+
throw new RuntimeException(o_O);
369+
}
370+
}
371+
372+
if (configuredBeanNameGenerator != BeanNameGenerator.class) {
373+
return BeanUtils.instantiateClass((Class<? extends BeanNameGenerator>) configuredBeanNameGenerator);
374+
}
375+
376+
return null;
377+
}
324378
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ default <T> T getRequiredAttribute(String name, Class<T> type) {
174174
BootstrapMode getBootstrapMode();
175175

176176
/**
177-
* Returns a human readable description of the repository configuration source for error reporting purposes.
177+
* Returns a human-readable description of the repository configuration source for error reporting purposes.
178178
*
179179
* @return can be {@literal null}.
180180
* @since 2.3

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

+18
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import org.junit.jupiter.api.BeforeEach;
2525
import org.junit.jupiter.api.Test;
2626
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
27+
import org.springframework.beans.factory.support.RootBeanDefinition;
2728
import org.springframework.context.annotation.ComponentScan.Filter;
29+
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;
2830
import org.springframework.context.annotation.Primary;
2931
import org.springframework.core.env.Environment;
3032
import org.springframework.core.env.StandardEnvironment;
@@ -33,6 +35,8 @@
3335
import org.springframework.core.type.AnnotationMetadata;
3436
import org.springframework.core.type.StandardAnnotationMetadata;
3537
import org.springframework.data.repository.PagingAndSortingRepository;
38+
import org.springframework.data.repository.config.basepackage.repo.PersonRepository;
39+
import org.springframework.data.repository.core.support.DummyRepositoryFactory;
3640

3741
/**
3842
* Unit tests for {@link AnnotationRepositoryConfigurationSource}.
@@ -165,6 +169,17 @@ void lookupOfEmptyStringExposesAbsentValue() {
165169
.isThrownBy(() -> source.getRequiredAttribute("namedQueriesLocation", String.class));
166170
}
167171

172+
@Test // GH-3082
173+
void considerBeanNameGenerator() {
174+
175+
RootBeanDefinition bd = new RootBeanDefinition(DummyRepositoryFactory.class);
176+
bd.getConstructorArgumentValues().addGenericArgumentValue(PersonRepository.class);
177+
178+
assertThat(getConfigSource(ConfigurationWithBeanNameGenerator.class).generateBeanName(bd))
179+
.isEqualTo("org.springframework.data.repository.config.basepackage.repo.PersonRepository");
180+
assertThat(getConfigSource(DefaultConfiguration.class).generateBeanName(bd)).isEqualTo("personRepository");
181+
}
182+
168183
private AnnotationRepositoryConfigurationSource getConfigSource(Class<?> type) {
169184

170185
AnnotationMetadata metadata = new StandardAnnotationMetadata(type, true);
@@ -186,6 +201,9 @@ static class DefaultConfigurationWithNestedRepositories {}
186201
@EnableRepositories(excludeFilters = { @Filter(Primary.class) })
187202
static class ConfigurationWithExplicitFilter {}
188203

204+
@EnableRepositories(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
205+
static class ConfigurationWithBeanNameGenerator {}
206+
189207
@Retention(RetentionPolicy.RUNTIME)
190208
@interface SampleAnnotation {
191209

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

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.lang.annotation.Retention;
2020
import java.lang.annotation.RetentionPolicy;
2121

22+
import org.springframework.beans.factory.support.BeanNameGenerator;
2223
import org.springframework.context.annotation.ComponentScan.Filter;
2324
import org.springframework.context.annotation.Import;
2425
import org.springframework.data.repository.PagingAndSortingRepository;
@@ -43,6 +44,8 @@
4344

4445
Class<?> repositoryBaseClass() default PagingAndSortingRepository.class;
4546

47+
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
48+
4649
String namedQueriesLocation() default "";
4750

4851
String repositoryImplementationPostfix() default "Impl";

0 commit comments

Comments
 (0)