DATACMNS-168 - Allow customizing repository bean names.
The bean name is now resolved through inspecting Spring stereotype annotations and @Named on the repository interface. If none found we're still using the uncapitalized simple interface name as we did until now.
This commit is contained in:
@@ -104,12 +104,17 @@ public class RepositoryBeanDefinitionParser implements BeanDefinitionParser {
|
||||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||||
beanDefinition.setSource(configuration.getSource());
|
||||
|
||||
RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator();
|
||||
generator.setBeanClassLoader(parser.getReaderContext().getBeanClassLoader());
|
||||
|
||||
String beanName = generator.generateBeanName(beanDefinition, parser.getRegistry());
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Registering repository: " + configuration.getBeanId() + " - Interface: "
|
||||
+ configuration.getRepositoryInterface() + " - Factory: " + extension.getRepositoryFactoryClassName());
|
||||
LOG.debug("Registering repository: " + beanName + " - Interface: " + configuration.getRepositoryInterface()
|
||||
+ " - Factory: " + extension.getRepositoryFactoryClassName());
|
||||
}
|
||||
|
||||
BeanComponentDefinition definition = new BeanComponentDefinition(beanDefinition, configuration.getBeanId());
|
||||
BeanComponentDefinition definition = new BeanComponentDefinition(beanDefinition, beanName);
|
||||
parser.registerBeanComponent(definition);
|
||||
} catch (RuntimeException e) {
|
||||
handleError(e, configuration.getConfigurationSource().getElement(), parser.getReaderContext());
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.repository.config;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
@@ -33,6 +34,9 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class RepositoryBeanDefinitionRegistrarSupport implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
// see SPR-9568
|
||||
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
@@ -47,13 +51,15 @@ public abstract class RepositoryBeanDefinitionRegistrarSupport implements Import
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
AnnotationRepositoryConfigurationSource configuration = new AnnotationRepositoryConfigurationSource(
|
||||
annotationMetadata, getAnnotation());
|
||||
|
||||
RepositoryConfigurationExtension extension = getExtension();
|
||||
extension.registerBeansForRoot(registry, configuration);
|
||||
|
||||
RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator();
|
||||
generator.setBeanClassLoader(getBeanClassLoader(registry));
|
||||
|
||||
for (RepositoryConfiguration<AnnotationRepositoryConfigurationSource> repositoryConfiguration : extension
|
||||
.getRepositoryConfigurations(configuration, resourceLoader)) {
|
||||
|
||||
@@ -62,10 +68,20 @@ public abstract class RepositoryBeanDefinitionRegistrarSupport implements Import
|
||||
|
||||
extension.postProcess(definitionBuilder, configuration);
|
||||
|
||||
registry.registerBeanDefinition(repositoryConfiguration.getBeanId(), definitionBuilder.getBeanDefinition());
|
||||
String beanName = generator.generateBeanName(definitionBuilder.getBeanDefinition(), registry);
|
||||
registry.registerBeanDefinition(beanName, definitionBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private ClassLoader getBeanClassLoader(BeanDefinitionRegistry registry) {
|
||||
|
||||
if (registry instanceof ConfigurableListableBeanFactory) {
|
||||
return ((ConfigurableListableBeanFactory) registry).getBeanClassLoader();
|
||||
}
|
||||
|
||||
return resourceLoader.getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the annotation to obtain configuration information from. Will be wrappen into an
|
||||
* {@link AnnotationRepositoryConfigurationSource} so have a look at the constants in there for what annotation
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012 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
|
||||
*
|
||||
* http://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.repository.config;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Special {@link BeanNameGenerator} to create bean names for Spring Data repositories. Will delegate to an
|
||||
* {@link AnnotationBeanNameGenerator} but let the delegate work with a customized {@link BeanDefinition} to make sure
|
||||
* the repository interface is inspected and not the actual bean definition class.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryBeanNameGenerator implements BeanNameGenerator, BeanClassLoaderAware {
|
||||
|
||||
private static final BeanNameGenerator DELEGATE = new AnnotationBeanNameGenerator();
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader)
|
||||
*/
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.support.BeanNameGenerator#generateBeanName(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||
*/
|
||||
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
|
||||
|
||||
AnnotatedBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(getRepositoryInterfaceFrom(definition));
|
||||
return DELEGATE.generateBeanName(beanDefinition, registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type configured for the {@code repositoryInterface} property of the given bean definition. Uses a
|
||||
* potential {@link Class} being configured as is or tries to load a class with the given value's {@link #toString()}
|
||||
* representation.
|
||||
*
|
||||
* @param beanDefinition
|
||||
* @return
|
||||
*/
|
||||
private Class<?> getRepositoryInterfaceFrom(BeanDefinition beanDefinition) {
|
||||
|
||||
Object value = beanDefinition.getPropertyValues().getPropertyValue("repositoryInterface").getValue();
|
||||
|
||||
if (value instanceof Class<?>) {
|
||||
return (Class<?>) value;
|
||||
} else {
|
||||
try {
|
||||
return ClassUtils.forName(value.toString(), beanClassLoader);
|
||||
} catch (Exception o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.repository.config;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
|
||||
/**
|
||||
@@ -30,7 +31,9 @@ public interface RepositoryConfiguration<T extends RepositoryConfigurationSource
|
||||
* Returns the id of the {@link BeanDefinition} the repository shall be registered under.
|
||||
*
|
||||
* @return
|
||||
* @deprecated bean ids should be determined using a {@link BeanNameGenerator} during classpath scanning.
|
||||
*/
|
||||
@Deprecated
|
||||
String getBeanId();
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,6 @@ public class DefaultRepositoryConfigurationUnitTests {
|
||||
RepositoryConfiguration<RepositoryConfigurationSource> configuration = new DefaultRepositoryConfiguration<RepositoryConfigurationSource>(
|
||||
source, "com.acme.MyRepository");
|
||||
|
||||
assertThat(configuration.getBeanId(), is("myRepository"));
|
||||
assertThat(configuration.getConfigurationSource(), is(source));
|
||||
assertThat(configuration.getImplementationBeanName(), is("myRepositoryImpl"));
|
||||
assertThat(configuration.getImplementationClassName(), is("MyRepositoryImpl"));
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2012 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
|
||||
*
|
||||
* http://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.repository.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RepositoryBeanNameGenerator}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryBeanNameGeneratorUnitTest {
|
||||
|
||||
BeanNameGenerator generator;
|
||||
BeanDefinitionRegistry registry;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator();
|
||||
generator.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
this.generator = generator;
|
||||
this.registry = new DefaultListableBeanFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesPlainClassNameIfNoAnnotationPresent() {
|
||||
assertThat(generator.generateBeanName(getBeanDefinitionFor(MyRepository.class), registry), is("myRepository"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesAnnotationValueIfAnnotationPresent() {
|
||||
assertThat(generator.generateBeanName(getBeanDefinitionFor(AnnotatedInterface.class), registry), is("specialName"));
|
||||
}
|
||||
|
||||
private BeanDefinition getBeanDefinitionFor(Class<?> repositoryInterface) {
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(RepositoryFactoryBeanSupport.class);
|
||||
builder.addPropertyValue("repositoryInterface", repositoryInterface.getName());
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
interface PlainInterface {
|
||||
|
||||
}
|
||||
|
||||
@Named("specialName")
|
||||
interface AnnotatedInterface {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user