diff --git a/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java b/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java index 26d48ac2bd..9329b5bcef 100644 --- a/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java +++ b/src/main/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSource.java @@ -28,6 +28,7 @@ import javax.annotation.Nonnull; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.FilterType; import org.springframework.core.annotation.AnnotationAttributes; @@ -54,6 +55,7 @@ * @author Peter Rietzler * @author Jens Schauder * @author Mark Paluch + * @author Sascha Woo */ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigurationSourceSupport { @@ -65,11 +67,13 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura private static final String REPOSITORY_FACTORY_BEAN_CLASS = "repositoryFactoryBeanClass"; private static final String REPOSITORY_BASE_CLASS = "repositoryBaseClass"; private static final String CONSIDER_NESTED_REPOSITORIES = "considerNestedRepositories"; + private static final String BEAN_NAME_GENERATOR = "nameGenerator"; private final AnnotationMetadata configMetadata; private final AnnotationMetadata enableAnnotationMetadata; private final AnnotationAttributes attributes; private final ResourceLoader resourceLoader; + private final RepositoryBeanNameGenerator beanNameGenerator; private final boolean hasExplicitFilters; /** @@ -85,7 +89,7 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class annotation, ResourceLoader resourceLoader, Environment environment, BeanDefinitionRegistry registry) { - super(environment, ConfigurationUtils.getRequiredClassLoader(resourceLoader), registry); + super(environment, registry); Assert.notNull(metadata, "Metadata must not be null!"); Assert.notNull(annotation, "Annotation must not be null!"); @@ -97,10 +101,13 @@ public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Clas throw new IllegalStateException(String.format("Unable to obtain annotation attributes for %s!", annotation)); } + ClassLoader classLoader = ConfigurationUtils.getRequiredClassLoader(resourceLoader); + this.attributes = new AnnotationAttributes(annotationAttributes); this.enableAnnotationMetadata = new StandardAnnotationMetadata(annotation); this.configMetadata = metadata; this.resourceLoader = resourceLoader; + this.beanNameGenerator = getBeanNameGenerator(attributes.getClass(BEAN_NAME_GENERATOR), classLoader); this.hasExplicitFilters = hasExplicitFilters(attributes); } @@ -122,6 +129,15 @@ private static boolean hasExplicitFilters(AnnotationAttributes attributes) { return false; } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryConfigurationSource#generateBeanName() + */ + @Override + public String generateBeanName(BeanDefinition beanDefinition) { + return beanNameGenerator.generateBeanName(beanDefinition); + } + /* * (non-Javadoc) * @see org.springframework.data.repository.config.RepositoryConfigurationSource#getBasePackages() diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java index 2014a75589..2c4c5a1a18 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationSourceSupport.java @@ -15,6 +15,8 @@ */ package org.springframework.data.repository.config; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Collections; import org.springframework.beans.factory.config.BeanDefinition; @@ -24,6 +26,7 @@ import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.util.Streamable; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * Base class to implement {@link RepositoryConfigurationSource}s. @@ -32,31 +35,27 @@ * @author Thomas Darimont * @author Peter Rietzler * @author Jens Schauder + * @author Sascha Woo */ public abstract class RepositoryConfigurationSourceSupport implements RepositoryConfigurationSource { protected static final String DEFAULT_REPOSITORY_IMPL_POSTFIX = "Impl"; private final Environment environment; - private final RepositoryBeanNameGenerator beanNameGenerator; private final BeanDefinitionRegistry registry; /** * Creates a new {@link RepositoryConfigurationSourceSupport} with the given environment. * * @param environment must not be {@literal null}. - * @param classLoader must not be {@literal null}. * @param registry must not be {@literal null}. */ - public RepositoryConfigurationSourceSupport(Environment environment, ClassLoader classLoader, - BeanDefinitionRegistry registry) { + public RepositoryConfigurationSourceSupport(Environment environment, BeanDefinitionRegistry registry) { Assert.notNull(environment, "Environment must not be null!"); - Assert.notNull(classLoader, "ClassLoader must not be null!"); Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); this.environment = environment; - this.beanNameGenerator = new RepositoryBeanNameGenerator(classLoader); this.registry = registry; } @@ -94,9 +93,7 @@ public Streamable getExcludeFilters() { * @see org.springframework.data.repository.config.RepositoryConfigurationSource#getBeanNameGenerator() */ @Override - public String generateBeanName(BeanDefinition beanDefinition) { - return beanNameGenerator.generateBeanName(beanDefinition); - } + public abstract String generateBeanName(BeanDefinition beanDefinition); /** * Return the {@link TypeFilter}s to define which types to include when scanning for repositories. Default @@ -108,6 +105,15 @@ protected Iterable getIncludeFilters() { return Collections.emptySet(); } + protected RepositoryBeanNameGenerator getBeanNameGenerator(Class beanNameGenerator, ClassLoader classLoader) { + try { + Constructor ctor = ClassUtils.getConstructorIfAvailable(beanNameGenerator, ClassLoader.class); + return ctor.newInstance(classLoader); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new IllegalArgumentException("Unsupported bean name generator specified " + beanNameGenerator.toString()); + } + } + /** * Returns whether we should consider nested repositories, i.e. repository interface definitions nested in other * classes. diff --git a/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java b/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java index eba8adf2a9..363b14a705 100644 --- a/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java +++ b/src/main/java/org/springframework/data/repository/config/XmlRepositoryConfigurationSource.java @@ -18,6 +18,7 @@ import java.util.Collection; import java.util.Optional; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.env.Environment; import org.springframework.core.type.filter.TypeFilter; @@ -29,6 +30,7 @@ import org.springframework.data.util.Streamable; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.w3c.dom.Element; @@ -40,6 +42,7 @@ * @author Christoph Strobl * @author Peter Rietzler * @author Jens Schauder + * @author Sascha Woo */ public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSourceSupport { @@ -50,9 +53,11 @@ public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSou private static final String REPOSITORY_FACTORY_BEAN_CLASS_NAME = "factory-class"; private static final String REPOSITORY_BASE_CLASS_NAME = "base-class"; private static final String CONSIDER_NESTED_REPOSITORIES = "consider-nested-repositories"; + private static final String BEAN_NAME_GENERATOR = "name-generator"; private final Element element; private final ParserContext context; + private final RepositoryBeanNameGenerator beanNameGenerator; private final Collection includeFilters; private final Collection excludeFilters; @@ -66,7 +71,7 @@ public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSou */ public XmlRepositoryConfigurationSource(Element element, ParserContext context, Environment environment) { - super(environment, ConfigurationUtils.getRequiredClassLoader(context.getReaderContext()), context.getRegistry()); + super(environment, context.getRegistry()); Assert.notNull(element, "Element must not be null!"); @@ -76,6 +81,12 @@ public XmlRepositoryConfigurationSource(Element element, ParserContext context, TypeFilterParser parser = new TypeFilterParser(context.getReaderContext()); this.includeFilters = parser.parseTypeFilters(element, Type.INCLUDE); this.excludeFilters = parser.parseTypeFilters(element, Type.EXCLUDE); + this.beanNameGenerator = getBeanNameGenerator(); + } + + @Override + public String generateBeanName(BeanDefinition beanDefinition) { + return beanNameGenerator.generateBeanName(beanDefinition); } /* @@ -211,4 +222,22 @@ public Optional getAttribute(String name) { public boolean usesExplicitFilters() { return !(this.includeFilters.isEmpty() && this.excludeFilters.isEmpty()); } + + private RepositoryBeanNameGenerator getBeanNameGenerator() { + ClassLoader classLoader = ConfigurationUtils.getRequiredClassLoader(context.getReaderContext()); + + Optional attributeNameGenerator = getNullDefaultedAttribute(element, BEAN_NAME_GENERATOR); + if (!attributeNameGenerator.isPresent()) + return new RepositoryBeanNameGenerator(classLoader); + + try { + @SuppressWarnings("unchecked") + Class beanNameGenerator = (Class) // + ClassUtils.forName(attributeNameGenerator.get(), classLoader); + + return getBeanNameGenerator(beanNameGenerator, classLoader); + } catch (ClassNotFoundException | LinkageError e) { + throw new IllegalArgumentException("Unsupported bean name generator specified " + attributeNameGenerator); + } + } } diff --git a/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java b/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java index 2e620cd039..271b1443a8 100755 --- a/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/AnnotationRepositoryConfigurationSourceUnitTests.java @@ -41,6 +41,7 @@ * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Sascha Woo */ public class AnnotationRepositoryConfigurationSourceUnitTests { @@ -165,6 +166,8 @@ static class ConfigurationWithExplicitFilter {} Filter[] includeFilters() default {}; Filter[] excludeFilters() default {}; + + Class nameGenerator() default RepositoryBeanNameGenerator.class; } @SampleAnnotation diff --git a/src/test/java/org/springframework/data/repository/config/EnableRepositories.java b/src/test/java/org/springframework/data/repository/config/EnableRepositories.java index d6991138c6..018c1bea69 100644 --- a/src/test/java/org/springframework/data/repository/config/EnableRepositories.java +++ b/src/test/java/org/springframework/data/repository/config/EnableRepositories.java @@ -51,4 +51,6 @@ boolean considerNestedRepositories() default false; boolean limitImplementationBasePackages() default true; + + Class nameGenerator() default RepositoryBeanNameGenerator.class; }