From 2040247a114f95153618df4061405bb408a0f3c3 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 9 Aug 2024 11:18:43 +0200 Subject: [PATCH] Add support for using custom BeanNameGenerator. Closes: #1853 --- .../config/EnableJdbcRepositories.java | 9 ++ .../JdbcRepositoriesRegistrarUnitTests.java | 91 +++++++++++++++++++ .../config/EnableR2dbcRepositories.java | 8 ++ .../R2dbcRepositoryRegistrarUnitTests.java | 82 +++++++++++++++++ 4 files changed, 190 insertions(+) create mode 100644 spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/JdbcRepositoriesRegistrarUnitTests.java create mode 100644 spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryRegistrarUnitTests.java diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java index f250e84f37f..fee50940238 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java @@ -23,6 +23,7 @@ import java.lang.annotation.Target; import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Import; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean; @@ -40,6 +41,7 @@ * @author Fei Dong * @author Antoine Sauray * @author Diego Krupitza + * @author Christoph Strobl * @see AbstractJdbcConfiguration */ @Target(ElementType.TYPE) @@ -106,6 +108,13 @@ */ Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; + /** + * Configure a specific {@link BeanNameGenerator} to be used when creating the repository beans. + * @return the {@link BeanNameGenerator} to be used or the base {@link BeanNameGenerator} interface to indicate context default. + * @since 3.4 + */ + Class nameGenerator() default BeanNameGenerator.class; + /** * Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the * repositories infrastructure. diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/JdbcRepositoriesRegistrarUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/JdbcRepositoriesRegistrarUnitTests.java new file mode 100644 index 00000000000..128ad66aa21 --- /dev/null +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/config/JdbcRepositoriesRegistrarUnitTests.java @@ -0,0 +1,91 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.jdbc.repository.config; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.annotation.AnnotationBeanNameGenerator; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.repository.CrudRepository; + +/** + * @author Christoph Strobl + */ +public class JdbcRepositoriesRegistrarUnitTests { + + private BeanDefinitionRegistry registry; + + @BeforeEach + void setUp() { + registry = new DefaultListableBeanFactory(); + } + + @ParameterizedTest // GH-1853 + @MethodSource(value = { "args" }) + void configuresRepositoriesCorrectly(AnnotationMetadata metadata, String[] beanNames) { + + JdbcRepositoriesRegistrar registrar = new JdbcRepositoriesRegistrar(); + registrar.setResourceLoader(new DefaultResourceLoader()); + registrar.setEnvironment(new StandardEnvironment()); + registrar.registerBeanDefinitions(metadata, registry); + + Iterable names = Arrays.asList(registry.getBeanDefinitionNames()); + assertThat(names).contains(beanNames); + } + + static Stream args() { + return Stream.of( + Arguments.of(AnnotationMetadata.introspect(Config.class), + new String[] { "jdbcRepositoriesRegistrarUnitTests.PersonRepository" }), + Arguments.of(AnnotationMetadata.introspect(ConfigWithBeanNameGenerator.class), + new String[] { "jdbcRepositoriesRegistrarUnitTests.PersonREPO" })); + } + + @EnableJdbcRepositories(basePackageClasses = PersonRepository.class, considerNestedRepositories = true) + private class Config { + + } + + @EnableJdbcRepositories(basePackageClasses = PersonRepository.class, nameGenerator = MyBeanNameGenerator.class, + considerNestedRepositories = true) + private class ConfigWithBeanNameGenerator { + + } + + static class MyBeanNameGenerator extends AnnotationBeanNameGenerator { + + @Override + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + return super.generateBeanName(definition, registry).replaceAll("Repository", "REPO"); + } + } + + static class Person {} + + interface PersonRepository extends CrudRepository {} +} diff --git a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java index 4cbb9456bf1..7055851edc8 100644 --- a/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java +++ b/spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java @@ -23,6 +23,7 @@ import java.lang.annotation.Target; import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Import; import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean; @@ -116,6 +117,13 @@ */ Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; + /** + * Configure a specific {@link BeanNameGenerator} to be used when creating the repository beans. + * @return the {@link BeanNameGenerator} to be used or the base {@link BeanNameGenerator} interface to indicate context default. + * @since 3.4 + */ + Class nameGenerator() default BeanNameGenerator.class; + /** * Configures the name of the {@link org.springframework.data.r2dbc.core.R2dbcEntityOperations} bean to be used with * the repositories detected. diff --git a/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryRegistrarUnitTests.java b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryRegistrarUnitTests.java new file mode 100644 index 00000000000..b5df6cd7a61 --- /dev/null +++ b/spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryRegistrarUnitTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.r2dbc.repository.config; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.annotation.AnnotationBeanNameGenerator; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.type.AnnotationMetadata; + +/** + * @author Christoph Strobl + */ +public class R2dbcRepositoryRegistrarUnitTests { + + private BeanDefinitionRegistry registry; + + @BeforeEach + void setUp() { + registry = new DefaultListableBeanFactory(); + } + + @ParameterizedTest // GH-1853 + @MethodSource(value = { "args" }) + void configuresRepositoriesCorrectly(AnnotationMetadata metadata, String[] beanNames) { + + R2dbcRepositoriesRegistrar registrar = new R2dbcRepositoriesRegistrar(); + registrar.setResourceLoader(new DefaultResourceLoader()); + registrar.setEnvironment(new StandardEnvironment()); + registrar.registerBeanDefinitions(metadata, registry); + + Iterable names = Arrays.asList(registry.getBeanDefinitionNames()); + assertThat(names).contains(beanNames); + } + + static Stream args() { + return Stream.of(Arguments.of(AnnotationMetadata.introspect(Config.class), new String[] { "personRepository" }), + Arguments.of(AnnotationMetadata.introspect(ConfigWithBeanNameGenerator.class), new String[] { "personREPO" })); + } + + @EnableR2dbcRepositories(basePackageClasses = PersonRepository.class) + private class Config { + + } + + @EnableR2dbcRepositories(basePackageClasses = PersonRepository.class, nameGenerator = MyBeanNameGenerator.class) + private class ConfigWithBeanNameGenerator { + + } + + static class MyBeanNameGenerator extends AnnotationBeanNameGenerator { + + @Override + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + return super.generateBeanName(definition, registry).replaceAll("Repository", "REPO"); + } + } +}