diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java index 1ccb349cb..acda849ba 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionParser.java @@ -17,13 +17,9 @@ package org.springframework.data.repository.config; import static org.springframework.beans.factory.support.BeanDefinitionReaderUtils.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.ReaderContext; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; @@ -41,8 +37,6 @@ import org.w3c.dom.Element; */ public class RepositoryBeanDefinitionParser implements BeanDefinitionParser { - private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryBeanDefinitionParser.class); - private final RepositoryConfigurationExtension extension; /** @@ -65,15 +59,15 @@ public class RepositoryBeanDefinitionParser implements BeanDefinitionParser { try { Environment environment = parser.getDelegate().getEnvironment(); + ResourceLoader resourceLoader = parser.getReaderContext().getResourceLoader(); + XmlRepositoryConfigurationSource configSource = new XmlRepositoryConfigurationSource(element, parser, environment); + RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configSource, resourceLoader); - for (RepositoryConfiguration config : extension.getRepositoryConfigurations( - configSource, parser.getReaderContext().getResourceLoader())) { - registerGenericRepositoryFactoryBean(config, parser); + for (BeanComponentDefinition definition : delegate.registerRepositoriesIn(parser.getRegistry(), extension)) { + parser.registerBeanComponent(definition); } - extension.registerBeansForRoot(parser.getRegistry(), configSource); - } catch (RuntimeException e) { handleError(e, element, parser.getReaderContext()); } @@ -85,47 +79,6 @@ public class RepositoryBeanDefinitionParser implements BeanDefinitionParser { reader.error(e.getMessage(), reader.extractSource(source), e); } - /** - * Registers a generic repository factory bean for a bean with the given name and the provided configuration context. - * - * @param parser - * @param name - * @param context - */ - private void registerGenericRepositoryFactoryBean( - RepositoryConfiguration configuration, ParserContext parser) { - - ResourceLoader resourceLoader = parser.getReaderContext().getResourceLoader(); - BeanDefinitionRegistry registry = parser.getRegistry(); - - RepositoryBeanDefinitionBuilder definitionBuilder = new RepositoryBeanDefinitionBuilder(registry, extension, - resourceLoader); - - try { - - BeanDefinitionBuilder builder = definitionBuilder.build(configuration); - extension.postProcess(builder, configuration.getConfigurationSource()); - - AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); - beanDefinition.setSource(configuration.getSource()); - - RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator(); - generator.setBeanClassLoader(parser.getReaderContext().getBeanClassLoader()); - - String beanName = generator.generateBeanName(beanDefinition, registry); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Registering repository: " + beanName + " - Interface: " + configuration.getRepositoryInterface() - + " - Factory: " + extension.getRepositoryFactoryClassName()); - } - - BeanComponentDefinition definition = new BeanComponentDefinition(beanDefinition, beanName); - parser.registerBeanComponent(definition); - } catch (RuntimeException e) { - handleError(e, configuration.getConfigurationSource().getElement(), parser.getReaderContext()); - } - } - /** * Returns whether the given {@link BeanDefinitionRegistry} already contains a bean of the given type assuming the * bean name has been autogenerated. diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java index d49e65ea8..390eb64ca 100644 --- a/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java +++ b/src/main/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupport.java @@ -17,20 +17,15 @@ package org.springframework.data.repository.config; import java.lang.annotation.Annotation; -import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.EnvironmentAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.env.Environment; -import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * Base class to implement {@link ImportBeanDefinitionRegistrar}s to enable repository @@ -38,21 +33,11 @@ import org.springframework.util.ClassUtils; * @author Oliver Gierke */ public abstract class RepositoryBeanDefinitionRegistrarSupport implements ImportBeanDefinitionRegistrar, - BeanClassLoaderAware, ResourceLoaderAware, EnvironmentAware { + ResourceLoaderAware, EnvironmentAware { private ResourceLoader resourceLoader; - private ClassLoader beanClassLoader; private Environment environment; - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader) - */ - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - /* * (non-Javadoc) * @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org.springframework.core.io.ResourceLoader) @@ -77,72 +62,20 @@ public abstract class RepositoryBeanDefinitionRegistrarSupport implements Import */ public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { - Assert.notNull(annotationMetadata); - Assert.notNull(registry); + Assert.notNull(resourceLoader, "ResourceLoader must not be null!"); + Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null!"); + Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); // Guard against calls for sub-classes if (annotationMetadata.getAnnotationAttributes(getAnnotation().getName()) == null) { return; } - defaultExternalResources(registry); - AnnotationRepositoryConfigurationSource configurationSource = new AnnotationRepositoryConfigurationSource( annotationMetadata, getAnnotation(), environment); - RepositoryConfigurationExtension extension = getExtension(); - extension.registerBeansForRoot(registry, configurationSource); - - RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator(); - generator.setBeanClassLoader(beanClassLoader); - - RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader); - - for (RepositoryConfiguration configuration : extension - .getRepositoryConfigurations(configurationSource, resourceLoader)) { - - BeanDefinitionBuilder definitionBuilder = builder.build(configuration); - extension.postProcess(definitionBuilder, configurationSource); - - String beanName = generator.generateBeanName(definitionBuilder.getBeanDefinition(), registry); - registry.registerBeanDefinition(beanName, definitionBuilder.getBeanDefinition()); - } - } - - /** - * Workaround the lack of injectability of external resources into {@link ImportBeanDefinitionRegistrar}s in the - * Spring 3.1 timeline. We populate {@link #beanClassLoader} and default the {@link #resourceLoader} in case they - * haven't been set until a call to this method. - * - * @param registry must not be {@literal null}. - * @see SPR-9568 - */ - private void defaultExternalResources(BeanDefinitionRegistry registry) { - - if (beanClassLoader == null) { - this.beanClassLoader = getBeanClassLoader(registry); - } - - if (resourceLoader == null) { - this.resourceLoader = new DefaultResourceLoader(this.beanClassLoader); - } - } - - /** - * Returns the bean class loader contained in the given registry if it is a {@link ConfigurableBeanFactory}. Falls - * back to the {@link ResourceLoader}'s {@link ClassLoader} or the global default one if that one is {@literal null} - * in turn. - * - * @param registry must not be {@literal null}. - * @return - */ - private ClassLoader getBeanClassLoader(BeanDefinitionRegistry registry) { - - if (registry instanceof ConfigurableBeanFactory) { - return ((ConfigurableBeanFactory) registry).getBeanClassLoader(); - } - - return resourceLoader == null ? ClassUtils.getDefaultClassLoader() : resourceLoader.getClassLoader(); + RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(configurationSource, resourceLoader); + delegate.registerRepositoriesIn(registry, getExtension()); } /** diff --git a/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java new file mode 100644 index 000000000..6097a91da --- /dev/null +++ b/src/main/java/org/springframework/data/repository/config/RepositoryConfigurationDelegate.java @@ -0,0 +1,113 @@ +/* + * Copyright 2014 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 java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; + +/** + * Delegate for configuration integration to reuse the general way of detecting repositories. Customization is done by + * providing a configuration format specific {@link RepositoryConfigurationSource} (currently either XML or annotations + * are supported). The actual registration can then be triggered for different {@link RepositoryConfigurationExtension} + * s. + * + * @author Oliver Gierke + */ +public class RepositoryConfigurationDelegate { + + private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryConfigurationDelegate.class); + + private final RepositoryConfigurationSource configurationSource; + private final ResourceLoader resourceLoader; + private final BeanNameGenerator generator; + private final boolean isXml; + + /** + * Creates a new {@link RepositoryConfigurationDelegate} for the given {@link RepositoryConfigurationSource} and + * {@link ResourceLoader}. + * + * @param configurationSource must not be {@literal null}. + * @param resourceLoader must not be {@literal null}. + */ + public RepositoryConfigurationDelegate(RepositoryConfigurationSource configurationSource, + ResourceLoader resourceLoader) { + + this.isXml = configurationSource instanceof XmlRepositoryConfigurationSource; + boolean isAnnotation = configurationSource instanceof AnnotationRepositoryConfigurationSource; + + Assert.isTrue(isXml || isAnnotation, + "Configuration source must either be an Xml- or an AnnotationBasedConfigurationSource!"); + Assert.notNull(resourceLoader); + + RepositoryBeanNameGenerator generator = new RepositoryBeanNameGenerator(); + generator.setBeanClassLoader(resourceLoader.getClassLoader()); + + this.generator = generator; + this.configurationSource = configurationSource; + this.resourceLoader = resourceLoader; + } + + /** + * Registers the found repositories in the given {@link BeanDefinitionRegistry}. + * + * @param registry + * @param extension + * @return {@link BeanComponentDefinition}s for all repository bean definitions found. + */ + public List registerRepositoriesIn(BeanDefinitionRegistry registry, + RepositoryConfigurationExtension extension) { + + extension.registerBeansForRoot(registry, configurationSource); + + RepositoryBeanDefinitionBuilder builder = new RepositoryBeanDefinitionBuilder(registry, extension, resourceLoader); + List definitions = new ArrayList(); + + for (RepositoryConfiguration configuration : extension + .getRepositoryConfigurations(configurationSource, resourceLoader)) { + + BeanDefinitionBuilder definitionBuilder = builder.build(configuration); + + if (isXml) { + extension.postProcess(definitionBuilder, (XmlRepositoryConfigurationSource) configurationSource); + } else { + extension.postProcess(definitionBuilder, (AnnotationRepositoryConfigurationSource) configurationSource); + } + + AbstractBeanDefinition beanDefinition = definitionBuilder.getBeanDefinition(); + String beanName = generator.generateBeanName(beanDefinition, registry); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Registering repository: " + beanName + " - Interface: " + configuration.getRepositoryInterface() + + " - Factory: " + extension.getRepositoryFactoryClassName()); + } + + registry.registerBeanDefinition(beanName, beanDefinition); + definitions.add(new BeanComponentDefinition(beanDefinition, beanName)); + } + + return definitions; + } +} diff --git a/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java b/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java index b5aba3222..656e62f1a 100644 --- a/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java +++ b/src/test/java/org/springframework/data/repository/config/RepositoryBeanDefinitionRegistrarSupportUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2014 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. @@ -27,6 +27,7 @@ import org.mockito.runners.MockitoJUnitRunner; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport; @@ -87,6 +88,10 @@ public class RepositoryBeanDefinitionRegistrarSupportUnitTests { static class DummyRegistrar extends RepositoryBeanDefinitionRegistrarSupport { + DummyRegistrar() { + setResourceLoader(new DefaultResourceLoader()); + } + /* * (non-Javadoc) * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()