/* * Copyright 2012-2017 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.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.RootBeanDefinition; import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider; import org.springframework.util.Assert; /** * Builder to create {@link BeanDefinitionBuilder} instance to eventually create Spring Data repository instances. * * @author Oliver Gierke * @author Christoph Strobl * @author Peter Rietzler */ class RepositoryBeanDefinitionBuilder { private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryBeanDefinitionBuilder.class); private final BeanDefinitionRegistry registry; private final RepositoryConfigurationExtension extension; private final ResourceLoader resourceLoader; private final MetadataReaderFactory metadataReaderFactory; private final CustomRepositoryImplementationDetector implementationDetector; /** * Creates a new {@link RepositoryBeanDefinitionBuilder} from the given {@link BeanDefinitionRegistry}, * {@link RepositoryConfigurationExtension} and {@link ResourceLoader}. * * @param registry must not be {@literal null}. * @param extension must not be {@literal null}. * @param resourceLoader must not be {@literal null}. * @param environment must not be {@literal null}. */ public RepositoryBeanDefinitionBuilder(BeanDefinitionRegistry registry, RepositoryConfigurationExtension extension, ResourceLoader resourceLoader, Environment environment) { Assert.notNull(extension, "RepositoryConfigurationExtension must not be null!"); Assert.notNull(resourceLoader, "ResourceLoader must not be null!"); Assert.notNull(environment, "Environment must not be null!"); this.registry = registry; this.extension = extension; this.resourceLoader = resourceLoader; this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); this.implementationDetector = new CustomRepositoryImplementationDetector(metadataReaderFactory, environment, resourceLoader); } /** * Builds a new {@link BeanDefinitionBuilder} from the given {@link BeanDefinitionRegistry} and {@link ResourceLoader} * . * * @param configuration must not be {@literal null}. * @return */ public BeanDefinitionBuilder build(RepositoryConfiguration<?> configuration) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null!"); Assert.notNull(resourceLoader, "ResourceLoader must not be null!"); BeanDefinitionBuilder builder = BeanDefinitionBuilder .rootBeanDefinition(configuration.getRepositoryFactoryBeanClassName()); builder.getRawBeanDefinition().setSource(configuration.getSource()); builder.addConstructorArgValue(configuration.getRepositoryInterface()); builder.addPropertyValue("queryLookupStrategyKey", configuration.getQueryLookupStrategyKey()); builder.addPropertyValue("lazyInit", configuration.isLazyInit()); configuration.getRepositoryBaseClassName()// .ifPresent(it -> builder.addPropertyValue("repositoryBaseClass", it)); NamedQueriesBeanDefinitionBuilder definitionBuilder = new NamedQueriesBeanDefinitionBuilder( extension.getDefaultNamedQueryLocation()); configuration.getNamedQueriesLocation().ifPresent(definitionBuilder::setLocations); builder.addPropertyValue("namedQueries", definitionBuilder.build(configuration.getSource())); registerCustomImplementation(configuration).ifPresent(it -> { builder.addPropertyReference("customImplementation", it); builder.addDependsOn(it); }); RootBeanDefinition evaluationContextProviderDefinition = new RootBeanDefinition( ExtensionAwareEvaluationContextProvider.class); evaluationContextProviderDefinition.setSource(configuration.getSource()); builder.addPropertyValue("evaluationContextProvider", evaluationContextProviderDefinition); return builder; } private Optional<String> registerCustomImplementation(RepositoryConfiguration<?> configuration) { String beanName = configuration.getImplementationBeanName(); // Already a bean configured? if (registry.containsBeanDefinition(beanName)) { return Optional.of(beanName); } Optional<AbstractBeanDefinition> beanDefinition = implementationDetector.detectCustomImplementation( configuration.getImplementationClassName(), configuration.getBasePackages(), configuration.getExcludeFilters()); return beanDefinition.map(it -> { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Registering custom repository implementation: " + configuration.getImplementationBeanName() + " " + it.getBeanClassName()); } it.setSource(configuration.getSource()); registry.registerBeanDefinition(beanName, it); return beanName; }); } }