Skip to content

DATACMNS-1228 - Allow custom bean name generator #262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -54,6 +55,7 @@
* @author Peter Rietzler
* @author Jens Schauder
* @author Mark Paluch
* @author Sascha Woo
*/
public class AnnotationRepositoryConfigurationSource extends RepositoryConfigurationSourceSupport {

Expand All @@ -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;

/**
Expand All @@ -85,7 +89,7 @@ public class AnnotationRepositoryConfigurationSource extends RepositoryConfigura
public AnnotationRepositoryConfigurationSource(AnnotationMetadata metadata, Class<? extends Annotation> 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!");
Expand All @@ -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);
}

Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -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;
}

Expand Down Expand Up @@ -94,9 +93,7 @@ public Streamable<TypeFilter> 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
Expand All @@ -108,6 +105,15 @@ protected Iterable<TypeFilter> getIncludeFilters() {
return Collections.emptySet();
}

protected RepositoryBeanNameGenerator getBeanNameGenerator(Class<? extends RepositoryBeanNameGenerator> beanNameGenerator, ClassLoader classLoader) {
try {
Constructor<? extends RepositoryBeanNameGenerator> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -40,6 +42,7 @@
* @author Christoph Strobl
* @author Peter Rietzler
* @author Jens Schauder
* @author Sascha Woo
*/
public class XmlRepositoryConfigurationSource extends RepositoryConfigurationSourceSupport {

Expand All @@ -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<TypeFilter> includeFilters;
private final Collection<TypeFilter> excludeFilters;
Expand All @@ -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!");

Expand All @@ -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);
}

/*
Expand Down Expand Up @@ -211,4 +222,22 @@ public Optional<String> getAttribute(String name) {
public boolean usesExplicitFilters() {
return !(this.includeFilters.isEmpty() && this.excludeFilters.isEmpty());
}

private RepositoryBeanNameGenerator getBeanNameGenerator() {
ClassLoader classLoader = ConfigurationUtils.getRequiredClassLoader(context.getReaderContext());

Optional<String> attributeNameGenerator = getNullDefaultedAttribute(element, BEAN_NAME_GENERATOR);
if (!attributeNameGenerator.isPresent())
return new RepositoryBeanNameGenerator(classLoader);

try {
@SuppressWarnings("unchecked")
Class<? extends RepositoryBeanNameGenerator> beanNameGenerator = (Class<? extends RepositoryBeanNameGenerator>) //
ClassUtils.forName(attributeNameGenerator.get(), classLoader);

return getBeanNameGenerator(beanNameGenerator, classLoader);
} catch (ClassNotFoundException | LinkageError e) {
throw new IllegalArgumentException("Unsupported bean name generator specified " + attributeNameGenerator);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
* @author Sascha Woo
*/
public class AnnotationRepositoryConfigurationSourceUnitTests {

Expand Down Expand Up @@ -165,6 +166,8 @@ static class ConfigurationWithExplicitFilter {}
Filter[] includeFilters() default {};

Filter[] excludeFilters() default {};

Class<? extends RepositoryBeanNameGenerator> nameGenerator() default RepositoryBeanNameGenerator.class;
}

@SampleAnnotation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@
boolean considerNestedRepositories() default false;

boolean limitImplementationBasePackages() default true;

Class<? extends RepositoryBeanNameGenerator> nameGenerator() default RepositoryBeanNameGenerator.class;
}